From 594b5482454d34de1b46e1108361a4466641d5c8 Mon Sep 17 00:00:00 2001 From: Krzysztof Jamroz Date: Fri, 17 Apr 2020 00:17:37 +0200 Subject: [PATCH] feat(jsbattle): store current progress when registering --- .../app/services/UserStore.service.js | 12 +++ .../test/unit/UserStore.spec.js | 93 ++++++++++++++++++- .../jsbattle-webpage/features/auth.feature | 34 +++++++ packages/jsbattle-webpage/package.json | 2 +- .../src/actions/coreAction.js | 47 ++++++++-- .../jsbattle-webpage/src/lib/fetchFromApi.js | 9 +- packages/jsbattle/package.json | 4 +- 7 files changed, 185 insertions(+), 16 deletions(-) diff --git a/packages/jsbattle-server/app/services/UserStore.service.js b/packages/jsbattle-server/app/services/UserStore.service.js index ce210abf..8de9ab76 100644 --- a/packages/jsbattle-server/app/services/UserStore.service.js +++ b/packages/jsbattle-server/app/services/UserStore.service.js @@ -132,6 +132,18 @@ class UserStoreService extends Service { displayName: displayName, registered: true }); + + let initCalls = []; + let initChallenges = ctx.params.challenges || []; + let initScripts = ctx.params.scripts || []; + for(let challenge of initChallenges) { + initCalls.push(ctx.call('challenges.updateUserChallange', challenge)); + } + for(let script of initScripts) { + initCalls.push(ctx.call('scriptStore.createUserScript', script)); + } + await Promise.all(initCalls); + return ctx.call('auth.whoami', {}); } diff --git a/packages/jsbattle-server/test/unit/UserStore.spec.js b/packages/jsbattle-server/test/unit/UserStore.spec.js index 487de225..122c2d78 100644 --- a/packages/jsbattle-server/test/unit/UserStore.spec.js +++ b/packages/jsbattle-server/test/unit/UserStore.spec.js @@ -4,6 +4,9 @@ const ConfigBroker = require("../../app/lib/ConfigBroker.js"); const { ValidationError } = require("moleculer").Errors; const { MoleculerClientError } = require("moleculer").Errors; +const updateUserChallange = jest.fn(); +const createUserScript = jest.fn(); + const createTestToken = (user) => ({ id: (user ? user.id : '') || "123456", username: (user ? user.username : '') || "amy", @@ -14,13 +17,25 @@ describe("Test 'UserStore' service", () => { let config = { auth: { admins: [{provider: 'google', username: 'monica83' }] } }; let broker = new ConfigBroker({ logger: false }, config, false); broker.createService({ - name: 'auth', - actions: { + name: 'auth', + actions: { whoami: () => ({ }) } }) + broker.createService({ + name: 'challenges', + actions: { + updateUserChallange: updateUserChallange + } + }) + broker.createService({ + name: 'scriptStore', + actions: { + createUserScript: createUserScript + } + }) broker.loadService(__dirname + "../../../app/services/UserStore.service.js"); beforeAll(() => broker.start()); @@ -297,7 +312,81 @@ describe("Test 'UserStore' service", () => { broker.call("userStore.register", { username: 'monic_888724' }, {meta: {user: createTestToken(user2)}}) ).rejects.toThrow(ValidationError); + }); + it('submit challenge data when registering', async () => { + updateUserChallange.mockReset(); + let user = await broker.call("userStore.findOrCreate", {user: { + extUserId: 'google_306464422', + username: 'alfred9854', + provider: 'google', + displayName: "Alfred Allegro", + email: "alf@example.com", + registered: false, + role: 'user' + }}); + let result = await broker.call( + "userStore.register", + { + challenges: [ + { + challengeId: "challenge-11123423", + completed: true, + code: "// code 12345" + }, + { + challengeId: "challenge-222425", + completed: false, + code: "// code 2345452" + } + ] + }, + {meta: {user: createTestToken(user)}} + ); + + expect(updateUserChallange.mock.calls).toHaveLength(2); + expect(updateUserChallange.mock.calls[0][0].params).toHaveProperty('challengeId', "challenge-11123423"); + expect(updateUserChallange.mock.calls[0][0].params).toHaveProperty('completed', true); + expect(updateUserChallange.mock.calls[0][0].params).toHaveProperty('code', "// code 12345"); + expect(updateUserChallange.mock.calls[1][0].params).toHaveProperty('challengeId', "challenge-222425"); + expect(updateUserChallange.mock.calls[1][0].params).toHaveProperty('completed', false); + expect(updateUserChallange.mock.calls[1][0].params).toHaveProperty('code', "// code 2345452"); }); + + it('submit scripts data when registering', async () => { + createUserScript.mockReset(); + let user = await broker.call("userStore.findOrCreate", {user: { + extUserId: 'google_67345', + username: 'book2495', + provider: 'google', + displayName: "Book Mack", + email: "bm@example.com", + registered: false, + role: 'user' + }}); + let result = await broker.call( + "userStore.register", + { + scripts: [ + { + scriptName: 'pink', + code: "// pink code" + }, + { + scriptName: 'blue', + code: "// blue code" + } + ] + }, + {meta: {user: createTestToken(user)}} + ); + + expect(createUserScript.mock.calls).toHaveLength(2); + expect(createUserScript.mock.calls[0][0].params).toHaveProperty('scriptName', "pink"); + expect(createUserScript.mock.calls[0][0].params).toHaveProperty('code', "// pink code"); + expect(createUserScript.mock.calls[1][0].params).toHaveProperty('scriptName', "blue"); + expect(createUserScript.mock.calls[1][0].params).toHaveProperty('code', "// blue code"); + }); + }) }); diff --git a/packages/jsbattle-webpage/features/auth.feature b/packages/jsbattle-webpage/features/auth.feature index 8769d40f..72af5968 100644 --- a/packages/jsbattle-webpage/features/auth.feature +++ b/packages/jsbattle-webpage/features/auth.feature @@ -82,3 +82,37 @@ Feature: Auth And Click "guest" auth method Then "Challenges" section is selected in the navigation bar And challenge [1] are unlocked + + @integration_only + Scenario: submit chalenges when registering + Given JsBattle open in the browser + And "Challenges" section open + And battle quality set to "0" + And battle speed set to "50" + When open challenge 1 + And close challenge info + And type "<>" in AI Script editor + And battle is completed + And the challenge is won + And Click Sign in button + And Click "mock" auth method + And register form is shown + And type "mock-registred" in "#register-form #username" input + And type "Registered Mock User" in "#register-form #displayname" input + And click "#register-form button" + And "Challenges" section open + Then challenge [1, 2] are unlocked + + @integration_only + Scenario: submit scripts when registering + Given JsBattle open in the browser + And "Sandbox" section open + When click create tank button + And Click Sign in button + And Click "mock" auth method + And register form is shown + And type "mock-registred" in "#register-form #username" input + And type "Registered Mock User" in "#register-form #displayname" input + And click "#register-form button" + And "Sandbox" section open + Then list of AI scripts contains 1 items diff --git a/packages/jsbattle-webpage/package.json b/packages/jsbattle-webpage/package.json index 53c89d79..7643c246 100644 --- a/packages/jsbattle-webpage/package.json +++ b/packages/jsbattle-webpage/package.json @@ -25,7 +25,7 @@ "build:bundle": "webpack --config ./webpack.config.js --mode=production", "test": "npm run test:dom && npm run test:browser", "test:dom": "jest -b=3", - "test:browser": "cucumber-js -f ./features/support/SimpleFormatter.js --retry 3 --fail-fast --world-parameters '{\"mockserver\": true}'", + "test:browser": "cucumber-js --tags \"not @integration_only\" -f ./features/support/SimpleFormatter.js --retry 3 --fail-fast --world-parameters '{\"mockserver\": true}'", "test:browser-smoke": "cucumber-js -t @smoke -f ./features/support/SimpleFormatter.js --retry 3 --fail-fast --world-parameters '{\"mockserver\": true}'", "analyse": "webpack --profile --json --config ./webpack.config.js > bundle_stats.json && webpack-bundle-analyzer bundle_stats.json", "watch": "npm-watch", diff --git a/packages/jsbattle-webpage/src/actions/coreAction.js b/packages/jsbattle-webpage/src/actions/coreAction.js index eaa1b6a9..015b6283 100644 --- a/packages/jsbattle-webpage/src/actions/coreAction.js +++ b/packages/jsbattle-webpage/src/actions/coreAction.js @@ -1,4 +1,6 @@ import profileService from '../services/profileService.js'; +import challengeService from "../services/challengeService.js"; +import aiRepoService from "../services/aiRepoService.js"; import { SET_SIM_QUALITY_REQUEST, @@ -67,15 +69,42 @@ export const getUserProfile = () => { }; export const registerProfile = (username, displayName) => { - return fetchFromApi("/api/user/initData", "PROFILE_REGISTER", { - method: 'PATCH', - body: JSON.stringify({ - username, - displayName - }), - headers: { - 'Content-Type': 'application/json' - }, + return fetchFromApi("/api/user/initData", "PROFILE_REGISTER", async () => { + + let challenges = await challengeService.getChallengeList(challengeService.getCompletedChallenges()); + let scripts = await aiRepoService.getScriptNameList(); + + let i; + for(i=0; i < challenges.length; i++) { + let challengeDef = await challengeService.getChallengeDefinition(challenges[i].id); + challenges[i] = { + challengeId: challenges[i].id, + completed: challenges[i].completed, + code: challengeDef.code + }; + } + + for(i=0; i < scripts.length; i++) { + let scriptData = await aiRepoService.getScript(scripts[i].id); + scripts[i] = { + scriptName: scripts[i].scriptName, + code: scriptData.code + }; + } + + + return { + method: 'PATCH', + body: JSON.stringify({ + username, + displayName, + challenges, + scripts + }), + headers: { + 'Content-Type': 'application/json' + } + }; }); }; diff --git a/packages/jsbattle-webpage/src/lib/fetchFromApi.js b/packages/jsbattle-webpage/src/lib/fetchFromApi.js index 1ffdba3b..db2a34e6 100644 --- a/packages/jsbattle-webpage/src/lib/fetchFromApi.js +++ b/packages/jsbattle-webpage/src/lib/fetchFromApi.js @@ -7,13 +7,18 @@ function sequenceFetch(actionList) { }; } - function fetchFromApi(url, type, opts, localFetch) { return async (dispatch) => { localFetch = localFetch || fetch; dispatch({type: type + "_REQUEST"}); try { - let response = await localFetch(url, opts); + let opsData; + if(typeof opts == 'function') { + opsData = await opts(); + } else { + opsData = opts; + } + let response = await localFetch(url, opsData); if (!response.ok) { let responseText = await response.text(); return dispatch({type: type + "_FAILURE", payload: new Error(`Error ${response.status}: ${responseText || response.statusText}`), error: true}); diff --git a/packages/jsbattle/package.json b/packages/jsbattle/package.json index 6657c751..970d9b5b 100644 --- a/packages/jsbattle/package.json +++ b/packages/jsbattle/package.json @@ -14,8 +14,8 @@ "test:copy-webpage": "cpx './node_modules/jsbattle-webpage/features/**/*' ./test/features-webpage && cpx './test/pm2_steps.js' './test/features-webpage/step_definitions'", "test:copy-admin": "cpx './node_modules/jsbattle-admin/features/**/*' ./test/features-admin && cpx './test/pm2_steps.js' './test/features-admin/step_definitions'", "test:run-all": "npm run test:run-webpage && npm run test:run-admin", - "test:run-webpage": "cucumber-js --fail-fast -t @integration --retry 3 -f ./test/features-webpage/support/SimpleFormatter.js --world-parameters '{\"port\": 8100}' ./test/features-webpage", - "test:run-admin": "cucumber-js --fail-fast -t @integration --retry 3 -f ./test/features-admin/support/SimpleFormatter.js --world-parameters '{\"port\": 8100}' ./test/features-admin", + "test:run-webpage": "cucumber-js --fail-fast -t \"@integration or @integration_only\" --retry 3 -f ./test/features-webpage/support/SimpleFormatter.js --world-parameters '{\"port\": 8100}' ./test/features-webpage", + "test:run-admin": "cucumber-js --fail-fast -t \"@integration or @integration_only\" --retry 3 -f ./test/features-admin/support/SimpleFormatter.js --world-parameters '{\"port\": 8100}' ./test/features-admin", "test:prep": "npm run test:copy-webpage && npm run test:copy-admin" }, "repository": {