How to refactor loading JSON fixtures for simplicity
In bahmutov/sudoku I am loading two JSON fixtures to mock a method that creates the new board. This ensures the game always starts with the same numbers and generates the same image for visual testing.
After the first test passes, we can write a test that plays one or several moves, then another test that sets the entire board and wins the game, etc. All these tests will load the same two fixture files at the start.
it('wins the game', () => { // load the solved array // and set the initial array to be same without one move cy.fixture('solved-array').then(solvedArray => { const almostSolved = [...solvedArray] // by setting entry to "0" we effectively clear the cell almostSolved[0] = '0' cy.stub(UniqueSudoku, 'getUniqueSudoku').returns([almostSolved, solvedArray]) }) cy.clock() mount(<App />) ... }) })
beforeEach
Loading the same fixture files in every test?! We can do better. First, let's load the fixtures in the beforeEach hook and save them in the test context. We will need to change our test functions from arrow functions to actual function functions.
it('mocks board creation', function () { // ✅ works cy.stub(UniqueSudoku, 'getUniqueSudoku') .returns([this.initArray, this.solvedArray]) cy.clock() mount(<App />) ... })
it('plays a move', function () { // 🔥 DOES NOT WORK // this.initArray is undefined // this.solvedArray is undefined cy.stub(UniqueSudoku, 'getUniqueSudoku') .returns([this.initArray, this.solvedArray]) cy.clock() mount(<App />) ... })
The test runner runs the before hook before the very first test, sets the fixtures as properties, and the first test passes. Then the test runner clears the test context and runs the second test. Thus during the second test, the properties initArray and solvedArray are undefined.
To get around this problem, let's use closure variables.
I strongly recommend using closure variables instead of this properties. The closure variables are clearly visible and do not depend on function vs () => {} syntax.
imports
Another possible solution for JSON fixtures it to ... import them from the fixture file. Cypress will bundle the JSON files just fine.