diff --git a/bin/test-sorry-cypress.sh b/bin/test-sorry-cypress.sh new file mode 100755 index 00000000..d5045873 --- /dev/null +++ b/bin/test-sorry-cypress.sh @@ -0,0 +1,32 @@ +#!/bin/bash +cd client/ + +if [[ -z "${CYPRESS_API_URL+x}" ]]; then + echo "CYPRESS_API_URL not set" + exit 1 +fi +if [[ -z "${CYPRESS_RECORD_KEY+x}" ]]; then + echo "CYPRESS_RECORD_KEY not set" + exit 2 +fi + +now=`date +%F-%T` +build_id="skillbox-build-${now}" + +#CYPRESS_API_URL="https://iterativ-cypress-director.herokuapp.com/" +#cmd="" + +cmd() { + npx cy2 run --parallel --record --config-file cypress.frontend.json --ci-build-id ${build_id} +} + +#cmd + +for number in {1..6} +do + echo "running command ${number}" + cmd & +done + +wait +#exit 0 diff --git a/client/cypress.e2e.json b/client/cypress.e2e.json index 8e6ace33..ab9affa4 100644 --- a/client/cypress.e2e.json +++ b/client/cypress.e2e.json @@ -6,6 +6,7 @@ "mochaFile": "cypress/test-reports/e2e/cypress-results-[hash].xml", "toConsole": true }, + "projectId": "msk-ee", "integrationFolder": "cypress/integration/e2e", "$schema": "https://on.cypress.io/cypress.schema.json" } diff --git a/client/cypress.frontend.json b/client/cypress.frontend.json index c762d73b..39f08006 100644 --- a/client/cypress.frontend.json +++ b/client/cypress.frontend.json @@ -6,6 +6,7 @@ "mochaFile": "cypress/test-reports/frontend/cypress-results-[hash].xml", "toConsole": true }, + "projectId": "msk-fe", "integrationFolder": "cypress/integration/frontend", "$schema": "https://on.cypress.io/cypress.schema.json" } diff --git a/client/cypress/fixtures/mocks.js b/client/cypress/fixtures/mocks.js index 3260015b..b3a97856 100644 --- a/client/cypress/fixtures/mocks.js +++ b/client/cypress/fixtures/mocks.js @@ -3,48 +3,41 @@ const selectedClass = { name: 'Moordale', readOnly: false, code: 'XXXX', - members: [] + members: [], }; -let classMemberIndex = 0; +let idIndex = 0; -function* classMemberIdGenerator() { - while (classMemberIndex < 99) { - classMemberIndex += 1; - yield btoa(`ClassMemberNode:${classMemberIndex}`); +function* idGenerator(entity) { + while (true) { + console.log(`generating id for ${entity}, ${idIndex}`); + idIndex += 1; + yield btoa(`${entity}:${idIndex}`); } } -const classMemberIdIterator = classMemberIdGenerator(); +const classMemberIdIterator = idGenerator('ClassMemberNode'); +const chapterIdIterator = idGenerator('ChapterNode'); +const moduleIdIterator = idGenerator('ModuleNode'); +const contentBlockIdIterator = idGenerator('ContentBlockNode'); -const getClassMemberId = () => { - return classMemberIdIterator.next().value; -}; +const getClassMemberId = () => classMemberIdIterator.next().value; +const getChapterId = () => chapterIdIterator.next().value; +const getModuleId = () => moduleIdIterator.next().value; +const getContentBlockId = () => contentBlockIdIterator.next().value; export default { UUID: () => '123-456-789', GenericStreamFieldType: () => ({type: 'text_block', value: 'Generic Stream Field Type'}), DateTime: () => '2021-01-01Z10:01:23', SnapshotNode: () => ({ - // id: ID! - // module: ModuleNode! chapters: [], - // chapters: [SnapshotChapterNode] - // hiddenContentBlocks(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, title: String): ContentBlockNodeConnection! - // created: DateTime! - // creator: String! - // shared: Boolean! - // objectiveGroups: [SnapshotObjectiveGroupNode] - // hiddenObjectives(offset: Int, before: String, after: String, first: Int, last: Int, text: String): ObjectiveNodeConnection! title: 'MockSnapshotTitle', metaTitle: 'MockSnapshotMetaTitle', - // heroImage: String - // changes: SnapshotChangesNode - // mine: Boolean }), ChapterNode: () => ({ slug: 'chapter-slug', - id: 'chapter-id', + id: getChapterId(), title: 'chapter-title', description: 'chapter-description', @@ -55,7 +48,7 @@ export default { slug: 'content-block-slug', userCreated: false, type: '', - id: 'content-block-id', + id: getContentBlockId(), }), AssignmentNode: () => ({ id: 'assignment-id', @@ -69,12 +62,15 @@ export default { selectedClass, schoolClasses: { edges: [ - {node: selectedClass} - ] + {node: selectedClass}, + ], + }, + recentModules: { + edges: [] } }), SchoolClassNode: () => ({ - readOnly: false + readOnly: false, }), ClassMemberNode: () => ({ firstName: 'First Name', @@ -82,6 +78,21 @@ export default { active: true, isTeacher: false, isMe: false, - id: getClassMemberId() + id: getClassMemberId(), + }), + ModuleNode: () => ({ + title: 'Module Title', + slug: 'some slug', + metaTitle: 'Meta Title', + heroImage: '', + teaser: '', + intro: '', + assignments: {nodes: []}, + id: getModuleId(), + }), + TopicNode: () => ({ + modules: { + edges: [] + } }) }; diff --git a/client/cypress/fixtures/topics.json b/client/cypress/fixtures/topics.json deleted file mode 100644 index 0323f83a..00000000 --- a/client/cypress/fixtures/topics.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "topics": { - "edges": [ - { - "node": { - "id": "VG9waWNOb2RlOjU=", - "order": 1, - "title": "Geld und Kauf", - "slug": "geld-und-kauf", - "__typename": "TopicNode" - }, - "__typename": "TopicEdge" - }, - { - "node": { - "id": "VG9waWNOb2RlOjUz", - "order": 2, - "title": "Berufliche Grundbildung", - "slug": "berufliche-grundbildung", - "__typename": "TopicNode" - }, - "__typename": "TopicEdge" - } - ], - "__typename": "TopicConnection" - } -} diff --git a/client/cypress/integration/frontend/current-module.spec.js b/client/cypress/integration/frontend/current-module.spec.js index 833fc235..0f0e51d0 100644 --- a/client/cypress/integration/frontend/current-module.spec.js +++ b/client/cypress/integration/frontend/current-module.spec.js @@ -1,166 +1,205 @@ -const assignments = require('../../fixtures/assignments.json'); -const mePayload = require('../../fixtures/me.join-class.json'); -const topics = require('../../fixtures/topics.json'); -const baseTopic = require('../../fixtures/geld-und-kauf.json'); +const topics = [ + { + id: 'VG9waWNOb2RlOjU=', + order: 1, + title: 'Geld und Kauf', + slug: 'geld-und-kauf', + }, + { + id: 'VG9waWNOb2RlOjUz', + order: 2, + title: 'Berufliche Grundbildung', + slug: 'berufliche-grundbildung', + }, +]; -const moduleTeasers = require('../../fixtures/module-teasers.json'); -const fullModules = require('../../fixtures/full-modules.json'); +let recentModules = []; -const topic = { +const me = () => { + console.log('getting me'); + return { + lastModule: { + slug: 'lohn-und-budget', + id: 'last-module-id', + }, + lastTopic: { + id: 'VG9waWNOb2RlOjU=', + slug: 'geld-und-kauf', + }, + recentModules: { + edges: recentModules, + }, + }; +}; + +const getId = (id) => btoa(`ModuleNode:${id}`); + +const modules = { + [getId(1)]: { + title: 'Lohn und Budget', + metaTitle: 'Modul 1', + slug: 'lohn-und-budget', + id: getId(1), + }, + [getId(2)]: { + title: 'Geld', + metaTitle: 'Modul 2', + slug: 'geld', + id: getId(2), + }, + [getId(3)]: { + title: 'Lerntipps', + metaTitle: 'Modul 4', + slug: 'lerntipps', + id: getId(3), + }, + [getId(4)]: { + title: 'Random', + metaTitle: 'Modul 5', + slug: 'random', + id: getId(4), + }, +}; + +const slugs = { + 'lohn-und-budget': getId(1), + 'geld': getId(2), + 'lerntipps': getId(3), + 'random': getId(4), +}; + +const getModuleBySlug = (slug) => { + console.log('getModuleBySlug', slug); + const id = slugs[slug]; + console.log(id); + return modules[id]; +}; + +const moduleNodes = Object.values(modules).map(module => ({ + node: module, +})); +console.log(moduleNodes); + +const getTopic = () => ({ topic: { - ...baseTopic.topic, + title: 'Geld und Kauf', + id: 'VG9waWNOb2RlOjU=', + teaser: 'Topic 2', modules: { - '__typename': 'ModuleNodeConnection', - edges: [ - ...Object.values(moduleTeasers).map(module => { - return { - node: module, - __typename: 'ModuleNodeEdge', - }; - }), - ], + edges: moduleNodes, }, }, -}; +}); -const me = { - ...mePayload.me, - lastModule: { - // 'id': 'TW9kdWxlTm9kZToxNw==', - 'slug': 'lohn-und-budget', - '__typename': 'ModuleNode', - }, - lastTopic: { - 'id': 'VG9waWNOb2RlOjU=', - 'slug': 'geld-und-kauf', - '__typename': 'TopicNode', - }, - recentModules: { - 'edges': [], - '__typename': 'ModuleNodeConnection', - }, -}; - -const operations = { - MeQuery: variables => { - return { - me: { - ...me, - '__typename': 'UserNode', - 'permissions': [], - }, - }; +const getOperations = () => ({ + MeQuery: { + me: me(), }, AssignmentsQuery: { - assignments, + assignments: [], }, - ModulesQuery: variables => { - return { - module: fullModules[variables.slug], - }; - }, - TopicsQuery: topics, - Topic: topic, - UpdateLastTopic: { - 'updateLastTopic': { - 'topic': topic.topic, - '__typename': 'UpdateLastTopicPayload', + ModuleDetailsQuery: variables => ({module: getModuleBySlug(variables.slug)}), + TopicsQuery: { + topics: { + edges: topics.map(topic => ({node: topic})), }, }, - UpdateLastModule: variables => { + Topic: getTopic(), + UpdateLastTopic: () => { + const Topic = getTopic(); + const topic = Topic.topic; return { - updateLastModule: { - lastModule: moduleTeasers[variables.input.id], - __typename: 'UpdateLastModulePayload', + updateLastTopic: { + topic, }, }; }, -}; + NewsTeasers: { + newsTeasers: { + edges: [], + }, + }, + UpdateLastModule: ({input: {id}}) => { + const lastModule = modules[id]; + return { + updateLastModule: { + lastModule, + }, + }; + }, +}); -Cypress.Commands.add('checkHome', (n, skipHome) => { +const checkHome = (n, skipHome) => { + cy.log(`Checking if home has ${n} teasers`); if (!skipHome) { cy.get('[data-cy="home-link"]').click(); } cy.get('[data-cy=start-modules-list]').should('exist'); cy.get('[data-cy=start-module-teaser]').should('have.length', n); -}); +}; -Cypress.Commands.add('goToModule', (topicTitle, moduleMetaTitle) => { +const goToModule = (topicTitle, moduleMetaTitle) => { + cy.log(`Going to module ${moduleMetaTitle} in topic ${topicTitle}`); cy.get('[data-cy=open-sidebar-link]').click(); cy.contains(topicTitle).click(); cy.get('[data-cy=topic-title]').should('exist').should('contain', topicTitle); cy.contains(moduleMetaTitle).click(); -}); +}; describe('Current Module', () => { before(() => { - cy.server(); - - cy.task('getSchema').then(schema => { - cy.mockGraphql({ - schema, - // endpoint: '/api/graphql' - // mocks, - operations, - }); - }); - - // cy.mockGraphql({ - // schema: schema, - // // endpoint: '/api/graphql' - // operations, - // }); + cy.setup(); }); - // it('is set correctly', () => { - // cy.viewport('macbook-15'); - // - // cy.fakeLogin('ross.geller', 'test'); - // // cy.apolloLogin('ross.geller', 'test'); - // cy.visit('/'); - // - // // module list exists, but does not have anything in it - // cy.checkHome(0, true); - // cy.get('[data-cy=no-modules-yet]').should('exist').should('contain', 'Sie haben sich noch kein Modul angeschaut. Legen Sie jetzt los!'); - // - // cy.goToModule('Geld und Kauf', 'Modul 2'); - // cy.get('[data-cy=module-title]').should('contain', 'Geld'); - // cy.checkHome(1); - // cy.get('[data-cy=start-module-teaser]').first().should('contain', 'Geld'); - // - // cy.goToModule('Geld und Kauf', 'Modul 1'); - // cy.get('[data-cy=module-title]').should('contain', 'Lohn und Budget'); - // cy.checkHome(2); - // cy.get('[data-cy=start-module-teaser]').first().should('contain', 'Lohn und Budget'); - // cy.get('[data-cy=start-module-teaser]').eq(1).should('contain', 'Geld'); - // - // cy.goToModule('Geld und Kauf', 'Modul 4'); - // cy.get('[data-cy=module-title]').should('contain', 'Lerntipps'); - // cy.checkHome(3); - // cy.get('[data-cy=start-module-teaser]').first().should('contain', 'Lerntipps'); - // cy.get('[data-cy=start-module-teaser]').eq(1).should('contain', 'Lohn und Budget'); - // cy.get('[data-cy=start-module-teaser]').eq(2).should('contain', 'Geld'); - // - // // module list is full, should switch only the order around - // cy.goToModule('Geld und Kauf', 'Modul 2'); - // cy.get('[data-cy=module-title]').should('contain', 'Geld'); - // cy.checkHome(3); - // cy.get('[data-cy=start-module-teaser]').first().should('contain', 'Geld'); - // cy.get('[data-cy=start-module-teaser]').eq(1).should('contain', 'Lerntipps'); - // cy.get('[data-cy=start-module-teaser]').eq(2).should('contain', 'Lohn und Budget'); - // - // cy.goToModule('Geld und Kauf', 'Modul 5'); - // cy.get('[data-cy=module-title]').should('contain', 'Random'); - // cy.checkHome(3); - // cy.get('[data-cy=start-module-teaser]').first().should('contain', 'Random'); - // cy.get('[data-cy=start-module-teaser]').eq(1).should('contain', 'Geld'); - // cy.get('[data-cy=start-module-teaser]').eq(2).should('contain', 'Lerntipps'); - // - // cy.get('[data-cy=start-module-teaser]').last().click(); - // cy.get('[data-cy=module-title]').should('contain', 'Lerntipps'); - // cy.checkHome(3); - // cy.get('[data-cy=start-module-teaser]').first().should('contain', 'Lerntipps'); - // cy.get('[data-cy=start-module-teaser]').eq(1).should('contain', 'Random'); - // cy.get('[data-cy=start-module-teaser]').eq(2).should('contain', 'Geld'); - // }); + it('is set correctly', () => { + cy.mockGraphqlOps({ + operations: getOperations(), + }); + + cy.visit('/'); + + // module list exists, but does not have anything in it + checkHome(0, true); + cy.get('[data-cy=no-modules-yet]').should('exist').should('contain', 'Sie haben sich noch kein Modul angeschaut. Legen Sie jetzt los!'); + + goToModule('Geld und Kauf', 'Modul 2'); + cy.get('[data-cy=module-title]').should('contain', 'Geld'); + checkHome(1); + cy.get('[data-cy=start-module-teaser]').first().should('contain', 'Geld'); + + goToModule('Geld und Kauf', 'Modul 1'); + cy.get('[data-cy=module-title]').should('contain', 'Lohn und Budget'); + checkHome(2); + cy.get('[data-cy=start-module-teaser]').first().should('contain', 'Lohn und Budget'); + cy.get('[data-cy=start-module-teaser]').eq(1).should('contain', 'Geld'); + + goToModule('Geld und Kauf', 'Modul 4'); + cy.get('[data-cy=module-title]').should('contain', 'Lerntipps'); + checkHome(3); + cy.get('[data-cy=start-module-teaser]').first().should('contain', 'Lerntipps'); + cy.get('[data-cy=start-module-teaser]').eq(1).should('contain', 'Lohn und Budget'); + cy.get('[data-cy=start-module-teaser]').eq(2).should('contain', 'Geld'); + + // module list is full, should switch only the order around + goToModule('Geld und Kauf', 'Modul 2'); + cy.get('[data-cy=module-title]').should('contain', 'Geld'); + checkHome(3); + cy.get('[data-cy=start-module-teaser]').first().should('contain', 'Geld'); + cy.get('[data-cy=start-module-teaser]').eq(1).should('contain', 'Lerntipps'); + cy.get('[data-cy=start-module-teaser]').eq(2).should('contain', 'Lohn und Budget'); + + goToModule('Geld und Kauf', 'Modul 5'); + cy.get('[data-cy=module-title]').should('contain', 'Random'); + checkHome(3); + cy.get('[data-cy=start-module-teaser]').first().should('contain', 'Random'); + cy.get('[data-cy=start-module-teaser]').eq(1).should('contain', 'Geld'); + cy.get('[data-cy=start-module-teaser]').eq(2).should('contain', 'Lerntipps'); + + cy.get('[data-cy=start-module-teaser]').last().click(); + cy.get('[data-cy=module-title]').should('contain', 'Lerntipps'); + checkHome(3); + cy.get('[data-cy=start-module-teaser]').first().should('contain', 'Lerntipps'); + cy.get('[data-cy=start-module-teaser]').eq(1).should('contain', 'Random'); + cy.get('[data-cy=start-module-teaser]').eq(2).should('contain', 'Geld'); + }); }); diff --git a/client/cypress/integration/frontend/custom-content-block.spec.js b/client/cypress/integration/frontend/custom-content-block.spec.js index b59854d1..ab5f2cd5 100644 --- a/client/cypress/integration/frontend/custom-content-block.spec.js +++ b/client/cypress/integration/frontend/custom-content-block.spec.js @@ -1,18 +1,6 @@ import getMe from '../../fixtures/me.minimal'; import module from '../../fixtures/module.minimal'; -import mocks from '../../fixtures/mocks'; -// title: String -// slug: String! -// hiddenFor: [SchoolClassNode] -// visibleFor: [SchoolClassNode] -// userCreated: Boolean! -// contents: GenericStreamFieldType -// type: String -// id: ID! -// mine: Boolean -// bookmarks: [ContentBlockBookmarkNode] -// originalCreator: PublicUserNode const chapters = [{ title: 'ABC', description: 'DEF', @@ -43,24 +31,17 @@ const operations = { describe('Custom Content Block', () => { before(() => { - cy.task('getSchema').then(schema => { - cy.mockGraphql({ - schema, - mocks, - operations, - }); - }); - cy.viewport('macbook-15'); + cy.setup(); }); - it.skip('Deletes the custom content block and removes it from the view', () => { + it('Deletes the custom content block and removes it from the view', () => { cy.fakeLogin('ross.geller', 'test'); cy.visit('module/some-module'); cy.log('Toggling Edit Mode'); cy.getByDataCy('toggle-editing').click(); - cy.getByDataCy('module-title').should('exist'); + cy.getByDataCy('module-title').should('exist'); cy.get('.content-block').should('have.length', 1); cy.log('Opening More Menu'); diff --git a/client/cypress/tsconfig.json b/client/cypress/tsconfig.json index b1f04a7d..664dd406 100644 --- a/client/cypress/tsconfig.json +++ b/client/cypress/tsconfig.json @@ -3,7 +3,7 @@ "allowJs": true, "checkJs": true, "resolveJsonModule": true, - "lib": ["es2015", "dom"], + "lib": ["es2017", "dom"], "target": "ES5", "types": [ "cypress" diff --git a/client/package-lock.json b/client/package-lock.json index 18d7e721..b2061e92 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -7967,6 +7967,30 @@ "array-find-index": "^1.0.1" } }, + "cy2": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/cy2/-/cy2-1.2.1.tgz", + "integrity": "sha512-wT99aBDkMcsmbAYK6mwfDTbH43tN/hyaJ2NrLYfjid9bDTx3rn7UaPKWOIRZtT7L2v32zbMp/GTRtHO3HWb23Q==", + "requires": { + "js-yaml": "^4.0.0", + "npm-which": "^3.0.1" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + } + } + }, "cyclist": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", @@ -16090,6 +16114,14 @@ "npm-bundled": "^1.0.1" } }, + "npm-path": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-2.0.4.tgz", + "integrity": "sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw==", + "requires": { + "which": "^1.2.10" + } + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -16098,6 +16130,16 @@ "path-key": "^2.0.0" } }, + "npm-which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-which/-/npm-which-3.0.1.tgz", + "integrity": "sha1-kiXybsOihcIJyuZ8OxGmtKtxQKo=", + "requires": { + "commander": "^2.9.0", + "npm-path": "^2.0.2", + "which": "^1.2.10" + } + }, "npmlog": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", diff --git a/client/package.json b/client/package.json index 21629fe5..a95b16e9 100644 --- a/client/package.json +++ b/client/package.json @@ -19,7 +19,8 @@ "cypress:e2e:test": "cypress run --config-file cypress.e2e.json", "cypress:frontend:test": "cypress run --config-file cypress.frontend.json", "install:cypress": "cypress install", - "test:unit": "jest" + "test:unit": "jest", + "cypress:parallel": "CYPRESS_API_URL=\"https://iterativ-cypress-director.herokuapp.com/\" cy2 run --parallel --record --key somekey --config-file cypress.frontend.json --ci-build-id some-id" }, "dependencies": { "@babel/core": "^7.5.4", @@ -44,6 +45,7 @@ "chalk": "^2.0.1", "copy-webpack-plugin": "^4.0.1", "css-loader": "^0.28.0", + "cy2": "^1.2.1", "dayjs": "^1.10.4", "debounce": "^1.2.0", "eslint": "^4.15.0", diff --git a/client/src/pages/module/module.vue b/client/src/pages/module/module.vue index 37d8c388..a0a8de62 100644 --- a/client/src/pages/module/module.vue +++ b/client/src/pages/module/module.vue @@ -1,9 +1,13 @@