diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 1a4e0a5..0b76f45 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -33,6 +33,9 @@ jobs: - name: Install dependencies for server run: cd server && yarn --frozen-lockfile + - name: Build + run: yarn build + - name: Cache build folder uses: actions/upload-artifact@v4 with: diff --git a/src/tests/e2e/about.cy.js b/src/tests/e2e/about.cy.js index aa25f75..7c5cbe6 100644 --- a/src/tests/e2e/about.cy.js +++ b/src/tests/e2e/about.cy.js @@ -6,7 +6,6 @@ describe("The about page", () => { .get("a") .contains("About the app") .realClick() - .wait(500) .root() .should("contain", "Dominik") .get("a") diff --git a/src/tests/e2e/game.cy.js b/src/tests/e2e/game.cy.js index a141489..d2cff16 100644 --- a/src/tests/e2e/game.cy.js +++ b/src/tests/e2e/game.cy.js @@ -1,18 +1,18 @@ -import { convertQuestions } from '../../../server/utils.js'; +import { convertQuestions } from "../../../server/utils.js"; -function escapeRegex(str = '') { - return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +function escapeRegex(str = "") { + return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } -describe('The game', () => { - beforeEach( () => { - cy.fixture('signals-staging.json').as('signals'); - cy.visit('http://localhost:3000'); +describe("The game", () => { + beforeEach(() => { + cy.fixture("signals-staging.json").as("signals"); + cy.visit("http://localhost:3000"); }); - it('should count score and rounds in image2text mode', function() { + it("should count score and rounds in image2text mode", function () { // getting data from our fixtures - const SIGNALS = convertQuestions( this.signals ); + const SIGNALS = convertQuestions(this.signals); const SIGNALLENGTH = this.signals.length; // some hoisting of variables so our (fake) promises have access to them let $title; @@ -23,26 +23,34 @@ describe('The game', () => { let score = 0; let position = 0; - cy - .get('[data-round]').should( 'contain', '1' ) + cy.get("[data-round]") + .should("contain", "1") // we check that all remaining progress steps display in future state and that all are there - .get('[data-progress-status]').should( $p => { - expect( $p ).to.have.length( SIGNALLENGTH ); - expect( Cypress.$( $p[ 0 ] ).attr('data-progress-status') ).to.deep.eq('current'); + .get("[data-progress-status]") + .should(($p) => { + expect($p).to.have.length(SIGNALLENGTH); + expect(Cypress.$($p[0]).attr("data-progress-status")).to.deep.eq( + "current", + ); - const rest = [ ...new Array( SIGNALLENGTH ) ].map( ( _, item ) => Cypress.$( $p[ item ] ).attr('data-progress-status') ); - expect( rest ).to.deep.eq( [ 'current', ...new Array( SIGNALLENGTH - 1 ).fill('future') ] ); + const rest = [...new Array(SIGNALLENGTH)].map((_, item) => + Cypress.$($p[item]).attr("data-progress-status"), + ); + expect(rest).to.deep.eq([ + "current", + ...new Array(SIGNALLENGTH - 1).fill("future"), + ]); }) // first we go through an entire round programmatically - .wrap( new Array( SIGNALLENGTH ) ) - .each( () => { + .wrap(new Array(SIGNALLENGTH)) + .each(() => { cy.log(`========== ${position} ==========`); cy.get('[data-question="true"] title') // we get what the question is and store what the right and wrong answers are .then((title) => { $title = title; - const idAttr = $title.attr('id'); - questionID = '#' + idAttr.replace('-title', ''); + const idAttr = $title.attr("id"); + questionID = "#" + idAttr.replace("-title", ""); answerText = SIGNALS[questionID].text; const safeAnswer = escapeRegex(SIGNALS[questionID].text); @@ -50,115 +58,164 @@ describe('The game', () => { correct = new RegExp(`^${safeAnswer}$`); }) // we check the progress bar - .get('[data-progress-status]').should( $p => { - expect( $p ).to.have.length( SIGNALLENGTH ); - expect( Cypress.$( $p[ position ] ).attr('data-progress-status') ).to.deep.eq('current'); - if( position > 0 ) { - expect( Cypress.$( $p[ position - 1 ] ).attr('data-progress-status') ).to.deep.eq('wrong'); + .get("[data-progress-status]") + .should(($p) => { + expect($p).to.have.length(SIGNALLENGTH); + expect( + Cypress.$($p[position]).attr("data-progress-status"), + ).to.deep.eq("current"); + if (position > 0) { + expect( + Cypress.$($p[position - 1]).attr("data-progress-status"), + ).to.deep.eq("wrong"); } }) // we click the wrong answer .then(() => { - score --; - cy.contains('button[data-answer=""]', wrongs).realClick() - // check the score has now one less - .get('[data-score]').should( 'contain', score ) - // check that there is no "Next Question" button visible - .get('button[data-cy-id="Next question"]').should( 'not.be.visible' ); + score--; + cy.contains('button[data-answer=""]', wrongs) + .realClick() + // check the score has now one less + .get("[data-score]") + .should("contain", score) + // check that there is no "Next Question" button visible + .get('button[data-cy-id="Next question"]') + .should("not.be.visible"); }) // we click the wrong answer .then(() => { - score --; - cy.contains('button[data-answer=""]', wrongs).realClick() - // check the score has now one less - .get('[data-score]').should( 'contain', score ) - // check that there is no "Next Question" button visible - .get('button[data-cy-id="Next question"]').should( 'not.be.visible' ); + score--; + cy.contains('button[data-answer=""]', wrongs) + .realClick() + // check the score has now one less + .get("[data-score]") + .should("contain", score) + // check that there is no "Next Question" button visible + .get('button[data-cy-id="Next question"]') + .should("not.be.visible"); }) .then(() => { - cy.contains('button[data-answer]', correct).each($btn => { + cy.contains("button[data-answer]", correct).each(($btn) => { cy.log($btn.text()); - }) + }); }) // we click the right answer .then(() => { - score ++; - cy.contains('button[data-answer]', correct).realClick().then(() => { - cy - // check the score has now one more - .get('[data-score]').should( 'contain', score ) - // check that there is no "Next Question" button visible - .get('[data-next]').should('be.visible') - .get('[data-answer]').should('be.disabled') - .get('[data-game-toggle]').should('be.disabled') - .get('[data-round-toggle]').should('be.disabled') - // now we click to go to the next question - .get('button[data-cy-id="Next question"]').filter(':visible').realClick() - // let's make sure the score is still the same - .get('[data-score]').should( 'contain', score ) - .get('[data-answer]').should('not.be.disabled') - .get('[data-game-toggle]').should('not.be.disabled') - .get('[data-round-toggle]').should('not.be.disabled'); - }) + score++; + cy.contains("button[data-answer]", correct) + .realClick() + .then(() => { + cy + // check the score has now one more + .get("[data-score]") + .should("contain", score) + // check that there is no "Next Question" button visible + .get("[data-next]") + .should("be.visible") + .get("[data-answer]") + .should("be.disabled") + .get("[data-game-toggle]") + .should("be.disabled") + .get("[data-round-toggle]") + .should("be.disabled") + // now we click to go to the next question + .get('button[data-cy-id="Next question"]') + .filter(":visible") + .realClick() + // let's make sure the score is still the same + .get("[data-score]") + .should("contain", score) + .get("[data-answer]") + .should("not.be.disabled") + .get("[data-game-toggle]") + .should("not.be.disabled") + .get("[data-round-toggle]") + .should("not.be.disabled"); + }); }) // this is where we iterate on the position for the next question - .wrap( null ).then( () => { - position ++; - }); + .then(() => { + position++; + }); }) // now that we have completed a round, let's check that it's also displayed - .get('[data-round]').should( 'contain', '2' ) + .get("[data-round]") + .should("contain", "2") // getting our questions and answers again - .wrap( null ).then( () => { + .then(() => { $title = Cypress.$('[data-question="true"] title'); - questionID = '#'+$title.attr('id').replace( '-title', '' ); - answerText = SIGNALS[ questionID ].text; - correct = new RegExp(`^(${ answerText })$`, 'g'); - wrongs = new RegExp(`^(?!${ answerText }$).*$`, 'gm'); + questionID = "#" + $title.attr("id").replace("-title", ""); + answerText = SIGNALS[questionID].text; + correct = new RegExp(`^(${answerText})$`, "g"); + wrongs = new RegExp(`^(?!${answerText}$).*$`, "gm"); }) // check the status bar which has now been restarted for the new round - .get('[data-progress-status]').should( $p => { + .get("[data-progress-status]") + .should(($p) => { position = 0; - expect( $p ).to.have.length( SIGNALLENGTH ); - expect( Cypress.$( $p[ position ] ).attr('data-progress-status') ).to.deep.eq('current'); - const rest = [ ...new Array( SIGNALLENGTH - position ) ].map( ( _, item ) => Cypress.$( $p[ item + position ] ).attr('data-progress-status') ); - expect( rest ).to.deep.eq( [ 'current', ...new Array( SIGNALLENGTH - position - 1 ).fill('future') ] ); + expect($p).to.have.length(SIGNALLENGTH); + expect(Cypress.$($p[position]).attr("data-progress-status")).to.deep.eq( + "current", + ); + const rest = [...new Array(SIGNALLENGTH - position)].map((_, item) => + Cypress.$($p[item + position]).attr("data-progress-status"), + ); + expect(rest).to.deep.eq([ + "current", + ...new Array(SIGNALLENGTH - position - 1).fill("future"), + ]); }) // now let's select the correct answer right away - .wrap( null ).then( () => { - cy.get('[data-answer]').contains( correct ).realClick(); + .then(() => { + cy.get("[data-answer]").contains(correct).realClick(); }) // we should have more score - .wrap( null ).then( () => { - score ++; - cy.get('[data-score]').should( 'contain', score ); + .then(() => { + score++; + cy.get("[data-score]").should("contain", score); }) // check the visibility and disable state - .get('[data-next]').should('be.visible') - .get('[data-answer]').should('be.disabled') - .get('[data-game-toggle]').should('be.disabled') - .get('[data-round-toggle]').should('be.disabled') - .get('button[data-cy-id="Next question"]').filter(':not(:visible)').should('not.be.visible') - .wait( 400 ) - .get('button[data-cy-id="Next question"]').filter(':visible').realClick() - .wrap( null ).then( () => { - cy.get('[data-score]').should( 'contain', score ); - }) - .get('[data-answer]').should('not.be.disabled') - .get('[data-game-toggle]').should('not.be.disabled') - .get('[data-round-toggle]').should('not.be.disabled') + .get("[data-next]") + .should("be.visible") + .get("[data-answer]") + .should("be.disabled") + .get("[data-game-toggle]") + .should("be.disabled") + .get("[data-round-toggle]") + .should("be.disabled") + .get('button[data-cy-id="Next question"]') + .filter(":not(:visible)") + .should("not.be.visible") + .wait(400) + .get('button[data-cy-id="Next question"]') + .filter(":visible") + .realClick() + .then(() => { + cy.get("[data-score]").should("contain", score); + }) + .get("[data-answer]") + .should("not.be.disabled") + .get("[data-game-toggle]") + .should("not.be.disabled") + .get("[data-round-toggle]") + .should("not.be.disabled") // now that we have answered the last question correctly it should be marked as such - .get('[data-progress-status]').should( $p => { - position ++; - expect( $p ).to.have.length( SIGNALLENGTH ); - expect( Cypress.$( $p[ position ] ).attr('data-progress-status') ).to.deep.eq('current'); - expect( Cypress.$( $p[ 0 ] ).attr('data-progress-status') ).to.deep.eq('right'); - }) + .get("[data-progress-status]") + .should(($p) => { + position++; + expect($p).to.have.length(SIGNALLENGTH); + expect(Cypress.$($p[position]).attr("data-progress-status")).to.deep.eq( + "current", + ); + expect(Cypress.$($p[0]).attr("data-progress-status")).to.deep.eq( + "right", + ); + }); }); - it('should count score and rounds in text2image mode', function() { + it("should count score and rounds in text2image mode", function () { // getting data from our fixtures - const SIGNALS = convertQuestions( this.signals ); + const SIGNALS = convertQuestions(this.signals); const QUESTIONS = this.signals; const SIGNALLENGTH = this.signals.length; // some hoisting of variables so our (fake) promises have access to them @@ -168,138 +225,201 @@ describe('The game', () => { let score = 0; let position = 0; - cy - .get('[data-round]').should( 'contain', '1' ) + cy.get("[data-round]") + .should("contain", "1") // we check that all remaining progress steps display in future state and that all are there - .get('[data-progress-status]').should( $p => { - expect( $p ).to.have.length( SIGNALLENGTH ); - expect( Cypress.$( $p[ 0 ] ).attr('data-progress-status') ).to.deep.eq('current'); + .get("[data-progress-status]") + .should(($p) => { + expect($p).to.have.length(SIGNALLENGTH); + expect(Cypress.$($p[0]).attr("data-progress-status")).to.deep.eq( + "current", + ); - const rest = [ ...new Array( SIGNALLENGTH ) ].map( ( _, item ) => Cypress.$( $p[ item ] ).attr('data-progress-status') ); - expect( rest ).to.deep.eq( [ 'current', ...new Array( SIGNALLENGTH - 1 ).fill('future') ] ); - }) - .get('[data-game-toggle-label]').realClick() + const rest = [...new Array(SIGNALLENGTH)].map((_, item) => + Cypress.$($p[item]).attr("data-progress-status"), + ); + expect(rest).to.deep.eq([ + "current", + ...new Array(SIGNALLENGTH - 1).fill("future"), + ]); + }) + .get("[data-game-toggle-label]") + .realClick() // first we go through an entire round programmatically - .wrap( new Array( SIGNALLENGTH ) ) - .each( () => { + .wrap(new Array(SIGNALLENGTH)) + .each(() => { cy // we get what the question is and store what the right and wrong answers are - .wrap( null ).then( () => { + .then(() => { $title = Cypress.$('[data-question="true"] span'); const questionImageID = $title.text(); - answerText = QUESTIONS.find( question => question.text === questionImageID ).image; + answerText = QUESTIONS.find( + (question) => question.text === questionImageID, + ).image; }) // we check the progress bar - .get('[data-progress-status]').should( $p => { - expect( $p ).to.have.length( SIGNALLENGTH ); - expect( Cypress.$( $p[ position ] ).attr('data-progress-status') ).to.deep.eq('current'); - if( position > 0 ) { - expect( Cypress.$( $p[ position - 1 ] ).attr('data-progress-status') ).to.deep.eq('wrong'); + .get("[data-progress-status]") + .should(($p) => { + expect($p).to.have.length(SIGNALLENGTH); + expect( + Cypress.$($p[position]).attr("data-progress-status"), + ).to.deep.eq("current"); + if (position > 0) { + expect( + Cypress.$($p[position - 1]).attr("data-progress-status"), + ).to.deep.eq("wrong"); } }) // we click the wrong answer - .wrap( null ).then( () => { - cy.get(`[data-answer=""] [data-id]:not([data-id="${ answerText }"])`, { timeout: 60000 }).eq( 0 ).realClick(); + .then(() => { + cy.get( + `[data-answer=""] [data-id]:not([data-id="${answerText}"])`, + { timeout: 60000 }, + ) + .eq(0) + .realClick(); }) // check the score has now one less - .wrap( null ).then( () => { - score --; - cy.get('[data-score]').should( 'contain', score ); + .then(() => { + score--; + cy.get("[data-score]").should("contain", score); }) // check that there is no "Next Question" button visible - .get('button[data-cy-id="Next question"]').should( 'not.be.visible' ) + .get('button[data-cy-id="Next question"]') + .should("not.be.visible") // click another wrong answer - .wrap( null ).then( () => { - cy.get(`[data-answer=""] [data-id]:not([data-id="${ answerText }"])`).eq( 1 ).realClick(); + .then(() => { + cy.get(`[data-answer=""] [data-id]:not([data-id="${answerText}"])`) + .eq(1) + .realClick(); }) // again score should have subtracted - .wrap( null ).then( () => { - score --; - cy.get('[data-score]').should( 'contain', score ); + .then(() => { + score--; + cy.get("[data-score]").should("contain", score); }) // check that there is no "Next Question" button visible - .get('button[data-cy-id="Next question"]').should( 'not.be.visible' ) + .get('button[data-cy-id="Next question"]') + .should("not.be.visible") // now we select the right answer - .wrap( null ).then( () => { - cy.get(`[data-answer=""] [data-id="${ answerText }"]`).realClick(); + .then(() => { + cy.get(`[data-answer=""] [data-id="${answerText}"]`).realClick(); }) // score now has one more point - .wrap( null ).then( () => { - score ++; - cy.get('[data-score]').should( 'contain', score ); + .then(() => { + score++; + cy.get("[data-score]").should("contain", score); }) // check that inputs are disabled - .get('[data-next]').should('be.visible') - .get('[data-answer]').should('be.disabled') - .get('[data-game-toggle]').should('be.disabled') - .get('[data-round-toggle]').should('be.disabled') - .get('button[data-cy-id="Next question"]').filter(':not(:visible)').should('not.be.visible') + .get("[data-next]") + .should("be.visible") + .get("[data-answer]") + .should("be.disabled") + .get("[data-game-toggle]") + .should("be.disabled") + .get("[data-round-toggle]") + .should("be.disabled") + .get('button[data-cy-id="Next question"]') + .filter(":not(:visible)") + .should("not.be.visible") // now we click to go to the next question - .get('button[data-cy-id="Next question"]', { timeout: 60000 }).filter(':visible').realClick() + .get('button[data-cy-id="Next question"]', { timeout: 60000 }) + .filter(":visible") + .realClick() // let's make sure the score is still the same - .wrap( null ).then( () => { - cy.get('[data-score]').should( 'contain', score ); + .then(() => { + cy.get("[data-score]").should("contain", score); }) // all inputs are clickable again - .get('[data-answer]').should('not.be.disabled') - .get('[data-game-toggle]').should('not.be.disabled') - .get('[data-round-toggle]').should('not.be.disabled') + .get("[data-answer]") + .should("not.be.disabled") + .get("[data-game-toggle]") + .should("not.be.disabled") + .get("[data-round-toggle]") + .should("not.be.disabled") // this is where we iterate on the position for the next question - .wrap( null ).then( () => { - position ++; - }); + .then(() => { + position++; + }); }) // now that we have completed a round, let's check that it's also displayed - .get('[data-round]').should( 'contain', '2' ) + .get("[data-round]") + .should("contain", "2") // getting our questions and answers again - .wrap( null ).then( () => { + .then(() => { $title = Cypress.$('[data-question="true"] span'); const questionImageID = $title.text(); - answerText = QUESTIONS.find( question => question.text === questionImageID ).image; + answerText = QUESTIONS.find( + (question) => question.text === questionImageID, + ).image; }) // check the status bar which has now been restarted for the new round - .get('[data-progress-status]').should( $p => { + .get("[data-progress-status]") + .should(($p) => { position = 0; - expect( $p ).to.have.length( SIGNALLENGTH ); - expect( Cypress.$( $p[ position ] ).attr('data-progress-status') ).to.deep.eq('current'); - const rest = [ ...new Array( SIGNALLENGTH - position ) ].map( ( _, item ) => Cypress.$( $p[ item + position ] ).attr('data-progress-status') ); - expect( rest ).to.deep.eq( [ 'current', ...new Array( SIGNALLENGTH - position - 1 ).fill('future') ] ); + expect($p).to.have.length(SIGNALLENGTH); + expect(Cypress.$($p[position]).attr("data-progress-status")).to.deep.eq( + "current", + ); + const rest = [...new Array(SIGNALLENGTH - position)].map((_, item) => + Cypress.$($p[item + position]).attr("data-progress-status"), + ); + expect(rest).to.deep.eq([ + "current", + ...new Array(SIGNALLENGTH - position - 1).fill("future"), + ]); }) // now let's select the correct answer right away - .wrap( null ).then( () => { - cy.get(`[data-answer=""] [data-id="${ answerText }"]`).realClick(); + .then(() => { + cy.get(`[data-answer=""] [data-id="${answerText}"]`).realClick(); }) // we should have more score - .wrap( null ).then( () => { - score ++; - cy.get('[data-score]').should( 'contain', score ); + .then(() => { + score++; + cy.get("[data-score]").should("contain", score); }) // check the visibility and disable state - .get('[data-next]').should('be.visible') - .get('[data-answer]').should('be.disabled') - .get('[data-game-toggle]').should('be.disabled') - .get('[data-round-toggle]').should('be.disabled') - .get('button[data-cy-id="Next question"]').filter(':not(:visible)').should('not.be.visible') - .wait( 400 ) - .get('button[data-cy-id="Next question"]').filter(':visible').realClick() - .wrap( null ).then( () => { - cy.get('[data-score]').should( 'contain', score ); - }) - .get('[data-answer]').should('not.be.disabled') - .get('[data-game-toggle]').should('not.be.disabled') - .get('[data-round-toggle]').should('not.be.disabled') + .get("[data-next]") + .should("be.visible") + .get("[data-answer]") + .should("be.disabled") + .get("[data-game-toggle]") + .should("be.disabled") + .get("[data-round-toggle]") + .should("be.disabled") + .get('button[data-cy-id="Next question"]') + .filter(":not(:visible)") + .should("not.be.visible") + .wait(400) + .get('button[data-cy-id="Next question"]') + .filter(":visible") + .realClick() + .then(() => { + cy.get("[data-score]").should("contain", score); + }) + .get("[data-answer]") + .should("not.be.disabled") + .get("[data-game-toggle]") + .should("not.be.disabled") + .get("[data-round-toggle]") + .should("not.be.disabled") // now that we have answered the last question correctly it should be marked as such - .get('[data-progress-status]').should( $p => { - position ++; - expect( $p ).to.have.length( SIGNALLENGTH ); - expect( Cypress.$( $p[ position ] ).attr('data-progress-status') ).to.deep.eq('current'); - expect( Cypress.$( $p[ 0 ] ).attr('data-progress-status') ).to.deep.eq('right'); - }) + .get("[data-progress-status]") + .should(($p) => { + position++; + expect($p).to.have.length(SIGNALLENGTH); + expect(Cypress.$($p[position]).attr("data-progress-status")).to.deep.eq( + "current", + ); + expect(Cypress.$($p[0]).attr("data-progress-status")).to.deep.eq( + "right", + ); + }); }); - it('should keep track of your wrong answers', function() { + it("should keep track of your wrong answers", function () { // getting data from our fixtures - const SIGNALS = convertQuestions( this.signals ); + const SIGNALS = convertQuestions(this.signals); const QUESTIONS = this.signals; const SIGNALLENGTH = this.signals.length; // some hoisting of variables so our (fake) promises have access to them @@ -311,167 +431,204 @@ describe('The game', () => { const history = []; let uniqeHistory; - cy - .get('[data-round]').should( 'contain', '1' ) - .get('[data-round-toggle]').should('be.disabled') + cy.get("[data-round]") + .should("contain", "1") + .get("[data-round-toggle]") + .should("be.disabled") // getting the current question from the DOM - .wrap( null ).then( () => { + .then(() => { $title = Cypress.$('[data-question="true"] title'); - questionID = '#'+$title.attr('id').replace( '-title', '' ); - history.push( questionID.substr( 1 ) ); - answerText = SIGNALS[ questionID ].text; - correct = new RegExp(`^(${ answerText })$`, 'g'); - wrongs = new RegExp(`^(?!${ answerText }$).*$`, 'gm'); + questionID = "#" + $title.attr("id").replace("-title", ""); + history.push(questionID.substr(1)); + answerText = SIGNALS[questionID].text; + correct = new RegExp(`^(${answerText})$`, "g"); + wrongs = new RegExp(`^(?!${answerText}$).*$`, "gm"); }) // wrong answer - .wrap( null ).then( () => { - cy.get('[data-answer=""]').contains( wrongs ).realClick(); + .then(() => { + cy.get('[data-answer=""]').contains(wrongs).realClick(); }) // wrong answer - .wrap( null ).then( () => { - cy.get('[data-answer=""]').contains( wrongs ).realClick(); + .then(() => { + cy.get('[data-answer=""]').contains(wrongs).realClick(); }) // wrong answer - .wrap( null ).then( () => { - cy.get('[data-answer=""]').contains( wrongs ).realClick(); + .then(() => { + cy.get('[data-answer=""]').contains(wrongs).realClick(); }) // correct answer - .wrap( null ).then( () => { - cy.get('[data-answer]').contains( correct ).realClick(); + .then(() => { + cy.get("[data-answer]").contains(correct).realClick(); }) // next question - .get('button[data-cy-id="Next question"]', { timeout: 60000 }).filter(':visible').realClick() + .get('button[data-cy-id="Next question"]', { timeout: 60000 }) + .filter(":visible") + .realClick() // getting the current question from the DOM - .wrap( null ).then( () => { + .then(() => { $title = Cypress.$('[data-question="true"] title'); - questionID = '#'+$title.attr('id').replace( '-title', '' ); - answerText = SIGNALS[ questionID ].text; - correct = new RegExp(`^(${ answerText })$`, 'g'); - wrongs = new RegExp(`^(?!${ answerText }$).*$`, 'gm'); + questionID = "#" + $title.attr("id").replace("-title", ""); + answerText = SIGNALS[questionID].text; + correct = new RegExp(`^(${answerText})$`, "g"); + wrongs = new RegExp(`^(?!${answerText}$).*$`, "gm"); }) // correct answer - .wrap( null ).then( () => { - cy.get('[data-answer]').contains( correct ).realClick(); + .then(() => { + cy.get("[data-answer]").contains(correct).realClick(); }) // next question - .get('button[data-cy-id="Next question"]', { timeout: 60000 }).filter(':visible').realClick() + .get('button[data-cy-id="Next question"]', { timeout: 60000 }) + .filter(":visible") + .realClick() // getting the current question from the DOM - .wrap( null ).then( () => { + .then(() => { $title = Cypress.$('[data-question="true"] title'); - questionID = '#'+$title.attr('id').replace( '-title', '' ); - history.push( questionID.substr( 1 ) ); - answerText = SIGNALS[ questionID ].text; - correct = new RegExp(`^(${ answerText })$`, 'g'); - wrongs = new RegExp(`^(?!${ answerText }$).*$`, 'gm'); + questionID = "#" + $title.attr("id").replace("-title", ""); + history.push(questionID.substr(1)); + answerText = SIGNALS[questionID].text; + correct = new RegExp(`^(${answerText})$`, "g"); + wrongs = new RegExp(`^(?!${answerText}$).*$`, "gm"); }) // wrong answer - .wrap( null ).then( () => { - cy.get('[data-answer=""]').contains( wrongs ).realClick(); + .then(() => { + cy.get('[data-answer=""]').contains(wrongs).realClick(); }) // correct answer - .wrap( null ).then( () => { - cy.get('[data-answer]').contains( correct ).realClick(); + .then(() => { + cy.get("[data-answer]").contains(correct).realClick(); }) // correct question - .get('button[data-cy-id="Next question"]', { timeout: 60000 }).filter(':visible').realClick() + .get('button[data-cy-id="Next question"]', { timeout: 60000 }) + .filter(":visible") + .realClick() // getting the current question from the DOM - .wrap( null ).then( () => { + .then(() => { $title = Cypress.$('[data-question="true"] title'); - questionID = '#'+$title.attr('id').replace( '-title', '' ); - history.push( questionID.substr( 1 ) ); - answerText = SIGNALS[ questionID ].text; - correct = new RegExp(`^(${ answerText })$`, 'g'); - wrongs = new RegExp(`^(?!${ answerText }$).*$`, 'gm'); + questionID = "#" + $title.attr("id").replace("-title", ""); + history.push(questionID.substr(1)); + answerText = SIGNALS[questionID].text; + correct = new RegExp(`^(${answerText})$`, "g"); + wrongs = new RegExp(`^(?!${answerText}$).*$`, "gm"); }) // wrong answer - .wrap( null ).then( () => { - cy.get('[data-answer=""]').contains( wrongs ).realClick(); + .then(() => { + cy.get('[data-answer=""]').contains(wrongs).realClick(); }) // toggle to text2image mode - .get('[data-game-toggle-label]').realClick() + .get("[data-game-toggle-label]") + .realClick() // getting the current question from the DOM - .wrap( null ).then( () => { + .then(() => { $title = Cypress.$('[data-question="true"] span'); const questionImageID = $title.text(); - answerText = QUESTIONS.find( question => question.text === questionImageID ).image; - history.push( answerText.substr( 1 ) ); + answerText = QUESTIONS.find( + (question) => question.text === questionImageID, + ).image; + history.push(answerText.substr(1)); }) // wrong answer - .wrap( null ).then( () => { - cy.get(`[data-answer=""] [data-id]:not([data-id="${ answerText }"])`).eq( 0 ).realClick(); + .then(() => { + cy.get(`[data-answer=""] [data-id]:not([data-id="${answerText}"])`) + .eq(0) + .realClick(); }) // correct answer - .wrap( null ).then( () => { - cy.get(`[data-answer=""] [data-id="${ answerText }"]`).realClick(); + .then(() => { + cy.get(`[data-answer=""] [data-id="${answerText}"]`).realClick(); }) // next question - .get('button[data-cy-id="Next question"]', { timeout: 60000 }).filter(':visible').realClick() + .get('button[data-cy-id="Next question"]', { timeout: 60000 }) + .filter(":visible") + .realClick() // getting the current question from the DOM - .wrap( null ).then( () => { + .then(() => { $title = Cypress.$('[data-question="true"] span'); const questionImageID = $title.text(); - answerText = QUESTIONS.find( question => question.text === questionImageID ).image; + answerText = QUESTIONS.find( + (question) => question.text === questionImageID, + ).image; }) // correct answer - .wrap( null ).then( () => { - cy.get(`[data-answer=""] [data-id="${ answerText }"]`).realClick(); + .then(() => { + cy.get(`[data-answer=""] [data-id="${answerText}"]`).realClick(); }) // next question - .get('button[data-cy-id="Next question"]', { timeout: 60000 }).filter(':visible').realClick() - .get('[data-round-toggle]').should( 'contain', 'Signals' ) + .get('button[data-cy-id="Next question"]', { timeout: 60000 }) + .filter(":visible") + .realClick() + .get("[data-round-toggle]") + .should("contain", "Signals") // go into round toggle - .get('[data-round-toggle]').realClick() - .get('[data-round-toggle-popup]').then( $item => { - uniqeHistory = [ ... new Set( history ) ]; - expect( $item, 'text content' ).to.contain.text(`wrong so far (${ uniqeHistory.length })`); + .get("[data-round-toggle]") + .realClick() + .get("[data-round-toggle-popup]") + .then(($item) => { + uniqeHistory = [...new Set(history)]; + expect($item, "text content").to.contain.text( + `wrong so far (${uniqeHistory.length})`, + ); }) // choose practice round - .get('button').contains('Practice').realClick() - .get('[data-round-toggle]').should( 'contain', 'Practice' ) + .get("button") + .contains("Practice") + .realClick() + .get("[data-round-toggle]") + .should("contain", "Practice") // now we iterate over all questions we answered wrong and check that they are all there - .wrap( null ).then( () => { - cy - .wrap( uniqeHistory ) - .each( () => { + .then(() => { + cy.wrap(uniqeHistory) + .each(() => { cy // getting the current question from the DOM - .wrap( null ).then( () => { + .then(() => { $title = Cypress.$('[data-question="true"] span'); const questionImageID = $title.text(); - answerText = QUESTIONS.find( question => question.text === questionImageID ).image; - expect( uniqeHistory.includes( answerText.substr( 1 ) ) ).to.be.true; + answerText = QUESTIONS.find( + (question) => question.text === questionImageID, + ).image; + expect(uniqeHistory.includes(answerText.substr(1))).to.be.true; }) // correct answer - .wrap( null ).then( () => { - cy.get(`[data-answer=""] [data-id="${ answerText }"]`).realClick(); + .then(() => { + cy.get( + `[data-answer=""] [data-id="${answerText}"]`, + ).realClick(); }) // next question - .get('button[data-cy-id="Next question"]', { timeout: 60000 }).filter(':visible').realClick() + .get('button[data-cy-id="Next question"]', { timeout: 60000 }) + .filter(":visible") + .realClick(); }) - .get('[data-round]').should( 'contain', '2' ) + .get("[data-round]") + .should("contain", "2") // let's go back to image2text mode - .get('[data-game-toggle-label]').realClick() - .get('[data-round]').should( 'contain', '2' ) - .wrap( uniqeHistory ) + .get("[data-game-toggle-label]") + .realClick() + .get("[data-round]") + .should("contain", "2") + .wrap(uniqeHistory) // now we check again that all questions we answered wrong earlier are in this round - .each( () => { + .each(() => { cy // getting the current question from the DOM - .wrap( null ).then( () => { + .then(() => { $title = Cypress.$('[data-question="true"] title'); - questionID = '#'+$title.attr('id').replace( '-title', '' ); - answerText = SIGNALS[ questionID ].text; - correct = new RegExp(`^(${ answerText })$`, 'g'); - expect( uniqeHistory.includes( questionID.substr( 1 ) ) ).to.be.true; + questionID = "#" + $title.attr("id").replace("-title", ""); + answerText = SIGNALS[questionID].text; + correct = new RegExp(`^(${answerText})$`, "g"); + expect(uniqeHistory.includes(questionID.substr(1))).to.be.true; }) // correct answer - .wrap( null ).then( () => { - cy.get('[data-answer]').contains( correct ).realClick(); + .then(() => { + cy.get("[data-answer]").contains(correct).realClick(); }) // next question - .get('button[data-cy-id="Next question"]', { timeout: 60000 }).filter(':visible').realClick() + .get('button[data-cy-id="Next question"]', { timeout: 60000 }) + .filter(":visible") + .realClick(); }) - .get('[data-round]').should( 'contain', '3' ) + .get("[data-round]") + .should("contain", "3"); }); }); }); diff --git a/src/tests/e2e/history.cy.js b/src/tests/e2e/history.cy.js index a564b0b..262c064 100644 --- a/src/tests/e2e/history.cy.js +++ b/src/tests/e2e/history.cy.js @@ -1,15 +1,15 @@ -import { convertQuestions } from '../../../server/utils.js'; +import { convertQuestions } from "../../../server/utils.js"; -describe('The history', () => { - beforeEach( () => { - cy.fixture('highscore-staging.json').as('highscore'); - cy.fixture('signals-staging.json').as('signals'); - cy.visit('http://localhost:3000'); +describe("The history", () => { + beforeEach(() => { + cy.fixture("highscore-staging.json").as("highscore"); + cy.fixture("signals-staging.json").as("signals"); + cy.visit("http://localhost:3000"); }); - it('should keep track of the wrong answers', function() { + it("should keep track of the wrong answers", function () { // getting data from our fixtures - const SIGNALS = convertQuestions( this.signals ); + const SIGNALS = convertQuestions(this.signals); const QUESTIONS = this.signals; const HIGHSCORE = this.highscore; // some hoisting of variables so our (fake) promises have access to them @@ -24,145 +24,185 @@ describe('The history', () => { cy // go into highscore - .get('a[data-highscore]').realClick() + .get("a[data-highscore]") + .realClick() // check that there are no user sections yet - .get('p[data-most-wrong]').should('not.exist') - .get('form[data-input-form]').should('not.exist') - .root().should( 'contain', 'Latest entries' ) - .root().should( 'contain', `Total: ${ HIGHSCORE.length }` ) - .root().should( 'contain', 'Score board' ) - .root().should( 'contain', 'Top 50' ) + .get("p[data-most-wrong]") + .should("not.exist") + .get("form[data-input-form]") + .should("not.exist") + .root() + .should("contain", "Latest entries") + .root() + .should("contain", `Total: ${HIGHSCORE.length}`) + .root() + .should("contain", "Score board") + .root() + .should("contain", "Top 50") // go back to game - .get('a').contains('Go back to the game').realClick() + .get("a") + .contains("Go back to the game") + .realClick() // getting the current question from the DOM - .wrap( null ).then( () => { + .then(() => { $title = Cypress.$('[data-question="true"] title'); - questionID = '#'+$title.attr('id').replace( '-title', '' ); - answerText = SIGNALS[ questionID ].text; - correct = new RegExp(`^(${ answerText })$`, 'g'); + questionID = "#" + $title.attr("id").replace("-title", ""); + answerText = SIGNALS[questionID].text; + correct = new RegExp(`^(${answerText})$`, "g"); }) // correct answer - .wrap( null ).then( () => { - cy.get('[data-answer]').contains( correct ).realClick(); + .then(() => { + cy.get("[data-answer]").contains(correct).realClick(); }) // next question - .get('button[data-cy-id="Next question"]', { timeout: 60000 }).filter(':visible').realClick() + .get('button[data-cy-id="Next question"]', { timeout: 60000 }) + .filter(":visible") + .realClick() // go into highscore - .get('a[data-highscore]').realClick() + .get("a[data-highscore]") + .realClick() // check what's displayed - .get('p[data-most-wrong]').should('not.exist') - .get('form[data-input-form]').should('be.visible') - .root().contains('pushups').should('not.exist') + .get("p[data-most-wrong]") + .should("not.exist") + .get("form[data-input-form]") + .should("be.visible") + .root() + .contains("pushups") + .should("not.exist") // go back to game - .get('a').contains('Go back to the game').realClick() + .get("a") + .contains("Go back to the game") + .realClick() // getting the current question from the DOM - .wrap( null ).then( () => { + .then(() => { $title = Cypress.$('[data-question="true"] title'); - questionID = '#'+$title.attr('id').replace( '-title', '' ); - answerText = SIGNALS[ questionID ].text; - correct = new RegExp(`^(${ answerText })$`, 'g'); - wrongs = new RegExp(`^(?!${ answerText }$).*$`, 'gm'); + questionID = "#" + $title.attr("id").replace("-title", ""); + answerText = SIGNALS[questionID].text; + correct = new RegExp(`^(${answerText})$`, "g"); + wrongs = new RegExp(`^(?!${answerText}$).*$`, "gm"); }) // wrong answer - .wrap( null ).then( () => { - wrongAnswers.push( answerText ); - cy.get('[data-answer=""]').contains( wrongs ).realClick(); + .then(() => { + wrongAnswers.push(answerText); + cy.get('[data-answer=""]').contains(wrongs).realClick(); }) // go into highscore - .get('a[data-highscore]').realClick() - .get('p[data-most-wrong]').should('be.visible') - .get('form[data-input-form]').should('be.visible') - .root().contains(' 5 pushups').should('be.visible') + .get("a[data-highscore]") + .realClick() + .get("p[data-most-wrong]") + .should("be.visible") + .get("form[data-input-form]") + .should("be.visible") + .root() + .contains(" 5 pushups") + .should("be.visible") // go back to game - .get('a').contains('Go back to the game').realClick() + .get("a") + .contains("Go back to the game") + .realClick() // correct answer - .wrap( null ).then( () => { - cy.get('[data-answer]').contains( correct ).realClick(); + .then(() => { + cy.get("[data-answer]").contains(correct).realClick(); }) // next question - .get('button[data-cy-id="Next question"]', { timeout: 60000 }).filter(':visible').realClick() + .get('button[data-cy-id="Next question"]', { timeout: 60000 }) + .filter(":visible") + .realClick() // getting the current question from the DOM - .wrap( null ).then( () => { + .then(() => { $title = Cypress.$('[data-question="true"] title'); - questionID = '#'+$title.attr('id').replace( '-title', '' ); - answerText = SIGNALS[ questionID ].text; - correct = new RegExp(`^(${ answerText })$`, 'g'); - wrongs = new RegExp(`^(?!${ answerText }$).*$`, 'gm'); + questionID = "#" + $title.attr("id").replace("-title", ""); + answerText = SIGNALS[questionID].text; + correct = new RegExp(`^(${answerText})$`, "g"); + wrongs = new RegExp(`^(?!${answerText}$).*$`, "gm"); }) // wrong answer - .wrap( null ).then( () => { - wrongAnswers.push( answerText ); - cy.get('[data-answer=""]').contains( wrongs ).realClick(); + .then(() => { + wrongAnswers.push(answerText); + cy.get('[data-answer=""]').contains(wrongs).realClick(); }) // correct answer - .wrap( null ).then( () => { - cy.get('[data-answer]').contains( correct ).realClick(); + .then(() => { + cy.get("[data-answer]").contains(correct).realClick(); }) // next question - .get('button[data-cy-id="Next question"]', { timeout: 60000 }).filter(':visible').realClick() + .get('button[data-cy-id="Next question"]', { timeout: 60000 }) + .filter(":visible") + .realClick() // getting the current question from the DOM - .wrap( null ).then( () => { + .then(() => { $title = Cypress.$('[data-question="true"] title'); - questionID = '#'+$title.attr('id').replace( '-title', '' ); - answerText = SIGNALS[ questionID ].text; - correct = new RegExp(`^(${ answerText })$`, 'g'); - wrongs = new RegExp(`^(?!${ answerText }$).*$`, 'gm'); + questionID = "#" + $title.attr("id").replace("-title", ""); + answerText = SIGNALS[questionID].text; + correct = new RegExp(`^(${answerText})$`, "g"); + wrongs = new RegExp(`^(?!${answerText}$).*$`, "gm"); }) // wrong answer - .wrap( null ).then( () => { - wrongAnswers.push( answerText ); - cy.get('[data-answer=""]').contains( wrongs ).realClick(); + .then(() => { + wrongAnswers.push(answerText); + cy.get('[data-answer=""]').contains(wrongs).realClick(); }) // correct answer - .wrap( null ).then( () => { - cy.get('[data-answer]').contains( correct ).realClick(); + .then(() => { + cy.get("[data-answer]").contains(correct).realClick(); }) // next question - .get('button[data-cy-id="Next question"]', { timeout: 60000 }).filter(':visible').realClick() + .get('button[data-cy-id="Next question"]', { timeout: 60000 }) + .filter(":visible") + .realClick() // getting the current question from the DOM - .wrap( null ).then( () => { + .then(() => { $title = Cypress.$('[data-question="true"] title'); - questionID = '#'+$title.attr('id').replace( '-title', '' ); - answerText = SIGNALS[ questionID ].text; - correct = new RegExp(`^(${ answerText })$`, 'g'); - wrongs = new RegExp(`^(?!${ answerText }$).*$`, 'gm'); + questionID = "#" + $title.attr("id").replace("-title", ""); + answerText = SIGNALS[questionID].text; + correct = new RegExp(`^(${answerText})$`, "g"); + wrongs = new RegExp(`^(?!${answerText}$).*$`, "gm"); }) // wrong answer - .wrap( null ).then( () => { - wrongAnswers.push( answerText ); - cy.get('[data-answer=""]').contains( wrongs ).realClick(); + .then(() => { + wrongAnswers.push(answerText); + cy.get('[data-answer=""]').contains(wrongs).realClick(); }) // correct answer - .wrap( null ).then( () => { - cy.get('[data-answer]').contains( correct ).realClick(); + .then(() => { + cy.get("[data-answer]").contains(correct).realClick(); }) // next question - .get('button[data-cy-id="Next question"]', { timeout: 60000 }).filter(':visible').realClick() + .get('button[data-cy-id="Next question"]', { timeout: 60000 }) + .filter(":visible") + .realClick() // getting the current question from the DOM - .wrap( null ).then( () => { + .then(() => { $title = Cypress.$('[data-question="true"] title'); - questionID = '#'+$title.attr('id').replace( '-title', '' ); - answerText = SIGNALS[ questionID ].text; - correct = new RegExp(`^(${ answerText })$`, 'g'); - wrongs = new RegExp(`^(?!${ answerText }$).*$`, 'gm'); + questionID = "#" + $title.attr("id").replace("-title", ""); + answerText = SIGNALS[questionID].text; + correct = new RegExp(`^(${answerText})$`, "g"); + wrongs = new RegExp(`^(?!${answerText}$).*$`, "gm"); }) // wrong answer - .wrap( null ).then( () => { - wrongAnswers.push( answerText ); - cy.get('[data-answer=""]').contains( wrongs ).realClick(); + .then(() => { + wrongAnswers.push(answerText); + cy.get('[data-answer=""]').contains(wrongs).realClick(); }) // go into highscore - .get('a[data-highscore]').realClick() + .get("a[data-highscore]") + .realClick() // check that the wrongs have been noted - .wrap( null ).then( () => { - cy - .get('ul[data-most-wrong-list]').should( 'contain', wrongAnswers[ 0 ] ) - .get('ul[data-most-wrong-list]').should( 'contain', wrongAnswers[ 1 ] ) - .get('ul[data-most-wrong-list]').should( 'contain', wrongAnswers[ 2 ] ) - .get('ul[data-most-wrong-list]').should( 'contain', wrongAnswers[ 3 ] ) - .get('ul[data-most-wrong-list]').should( 'contain', wrongAnswers[ 4 ] ) + .then(() => { + cy.get("ul[data-most-wrong-list]") + .should("contain", wrongAnswers[0]) + .get("ul[data-most-wrong-list]") + .should("contain", wrongAnswers[1]) + .get("ul[data-most-wrong-list]") + .should("contain", wrongAnswers[2]) + .get("ul[data-most-wrong-list]") + .should("contain", wrongAnswers[3]) + .get("ul[data-most-wrong-list]") + .should("contain", wrongAnswers[4]); }) // check for right pushup count (5*5) - .root().contains('25 pushups').should('be.visible') + .root() + .contains("25 pushups") + .should("be.visible"); }); }); diff --git a/src/tests/e2e/loading.cy.js b/src/tests/e2e/loading.cy.js index 3d80a8c..f367173 100644 --- a/src/tests/e2e/loading.cy.js +++ b/src/tests/e2e/loading.cy.js @@ -1,17 +1,17 @@ -describe('The main app', () => { - it('should load data into localStorage and retains it over browser refreshs', () => { - cy.visit('http://localhost:3000'); - expect( localStorage.getItem('questions') ).to.eq( null ); - expect( localStorage.getItem('svg') ).to.eq( null ); +describe("The main app", () => { + it("should load data into localStorage and retains it over browser refreshs", () => { + cy.visit("http://localhost:3000"); + expect(localStorage.getItem("questions")).to.eq(null); + expect(localStorage.getItem("svg")).to.eq(null); - cy.wait( 1000 ).then( () => { - expect( localStorage.getItem('questions') ).to.not.eq( null ); - expect( localStorage.getItem('svg') ).to.not.eq( null ); + cy.wait(1000).then(() => { + expect(localStorage.getItem("questions")).to.not.eq(null); + expect(localStorage.getItem("svg")).to.not.eq(null); cy.reload(); - expect( localStorage.getItem('questions') ).to.not.eq( null ); - expect( localStorage.getItem('svg') ).to.not.eq( null ); + expect(localStorage.getItem("questions")).to.not.eq(null); + expect(localStorage.getItem("svg")).to.not.eq(null); }); }); });