Friday, 24 June 2022

Web Tutorial: The Japanese Language Trainer App (Part 4/4)

The first test we will write for this app, is for App. So create App.test.js in the src directory.

We begin by importing these.

src/App.test.js
import React from "react";
import { render, screen } from '@testing-library/react';
import App from './App';


And the very first test, is for App to render. We test to see if that string appears in the screen. This, by itself, isn't a great test, but it will do for a start.

src/App.test.js
import React from "react";
import { render, screen } from '@testing-library/react';
import App from './App';

describe("App", () => {
    it('renders', () => {
        render(<App />);
        expect(screen.queryByText('Welcome to J-Trainer!')).toBeInTheDocument();
    });
});


Run npm test in the command line interface. This test should succeed.




Now we will test the Header component. Create Header.test.js in the Header directory of the components directory. We begin with the appropriate import statements.

src/components/Header/Header.test.js
import React from "react";
import { render, screen } from '@testing-library/react';
import userEvent from "@testing-library/user-event";
import Header from './Header';


We define the getters and setters, because these are passed to the components.

src/components/Header/Header.test.js
import React from "react";
import { render, screen } from '@testing-library/react';
import userEvent from "@testing-library/user-event";
import Header from './Header';

let maxRemaining;

let started;
let setStarted = (val)=> {
    started = val;
};

let charset;
let setCharset = (val)=> {
    charset = val;
};

let remaining;
let setRemaining = (val)=> {
    remaining = val;
};

let usedQuestions;
let setUsedQuestions = (val)=> {
    usedQuestions = val;
};

let answer;
let setAnswer = (val)=> {
    answer = val;
};

let result;
let setResult = (val)=> {
    result = val;
};

let question;
let setQuestion = (val)=> {
    question = val;
};


We then use the describe() function, and pass in "Header" and a callback as arguments.

src/components/Header/Header.test.js
let question;
let setQuestion = (val)=> {
    question = val;
};

describe("Header", () => {

});


The tests have an explanatory string passed in as an argument, and a callback. This makes it easy to see what the tests should test for.

src/components/Header/Header.test.js
describe("Header", () => {
    it("should render with BEGIN button if not started and no charset selected", () => {

    });
    
    it("should render with CANCEL button if started, charset selected, has questions remaining", () => {

    });

    it("should render with RESTART button if started, charset selected, has no questions remaining", () => {

    });

});


Time for the first test. We make sure that the operating conditions are as close to the actual operating conditions, by setting these variables. Note that started is now false and charset is null.

src/components/Header/Header.test.js
it("should render with BEGIN button if not started and no charset selected", () => {
    maxRemaining = 20;
    setCharset(null);
    setStarted(false);
    setUsedQuestions([]);
    setRemaining(maxRemaining);

});


We render the Header component with all the required attributes.

src/components/Header/Header.test.js
it("should render with BEGIN button if not started and no charset selected", () => {
    maxRemaining = 20;
    setCharset(null);
    setStarted(false);
    setUsedQuestions([]);
    setRemaining(maxRemaining);

    render(
    <Header
      charset={ charset }
      started={ started }
      remaining={ remaining }
      usedQuestions={ usedQuestions }
      maxRemaining={ maxRemaining }
      setStarted={ setStarted }
      setCharset={ setCharset }
      setRemaining={ setRemaining }
      setAnswer={ setAnswer }
      setResult={ setResult }
      setQuestion={ setQuestion }
      setUsedQuestions={ setUsedQuestions }
    />        
    );

});


And then we have two asserts. Use the expect() function. Ensure that the button's text is "BEGIN ➤" because started is false and it is disabled because charset is null.

src/components/Header/Header.test.js
it("should render with BEGIN button if not started and no charset selected", () => {
    maxRemaining = 20;
    setCharset(null);
    setStarted(false);
    setUsedQuestions([]);
    setRemaining(maxRemaining);

    render(
    <Header
      charset={ charset }
      started={ started }
      remaining={ remaining }
      usedQuestions={ usedQuestions }
      maxRemaining={ maxRemaining }
      setStarted={ setStarted }
      setCharset={ setCharset }
      setRemaining={ setRemaining }
      setAnswer={ setAnswer }
      setResult={ setResult }
      setQuestion={ setQuestion }
      setUsedQuestions={ setUsedQuestions }
    />        
    );

    expect(screen.getByTestId("BtnStartEnd").textContent).toBe("BEGIN ➤");
    expect(screen.getByTestId("BtnStartEnd")).toBeDisabled();

});


We will also need to add this to the button.

src/components/Header.js

if (started) {
    return (
        <>
            <div className="Title">
                <h1>J-Trainer</h1>
            </div>
            <div className="Controls">
                <div>
                    <br />
                    <button data-testid="BtnStartEnd" onClick={ ()=>{BtnEnd_click();}}>
                        { remaining === 0 ? "RESTART ➤ " : "CANCEL ☓" }
                    </button>
                </div>
            </div>
        </>            
    );
} else {
    return (
        <>
            <div className="Title">
                <h1>J-Trainer</h1>
            </div>
            <div className="Controls">
                <div>
                <input type="radio" name="charset" onClick={()=>{SetCurrentCharset('hiragana');}}  /> Hiragana <br />
                <input type="radio" name="charset" onClick={()=>{SetCurrentCharset('katakana');}} /> Katakana <br />
                <br />
                    <button data-testid="BtnStartEnd" onClick={ ()=>{BtnStart_click();}} disabled={ charset === null ? true : false }>
                        BEGIN ➤
                    </button>
                </div>
            </div>
        </>
    );          
}  


Now for the next test! Again, pass what we need to. Just make sure that remaining is more than 0 and charset is not null (even an empty array counts), and started is true.

src/components/Header/Header.test.js
it("should render with CANCEL button if started, charset selected, has questions remaining", () => {
    maxRemaining = 20;
    setCharset([]);
    setStarted(true);
    setUsedQuestions([]);
    setRemaining(maxRemaining);

});


Next, render the Header component with the appropriate attributes.

src/components/Header/Header.test.js
it("should render with CANCEL button if started, charset selected, has questions remaining", () => {
    maxRemaining = 20;
    setCharset([]);
    setStarted(true);
    setUsedQuestions([]);
    setRemaining(maxRemaining);

    render(
    <Header
      charset={ charset }
      started={ started }
      remaining={ remaining }
      usedQuestions={ usedQuestions }
      maxRemaining={ maxRemaining }
      setStarted={ setStarted }
      setCharset={ setCharset }
      setRemaining={ setRemaining }
      setAnswer={ setAnswer }
      setResult={ setResult }
      setQuestion={ setQuestion }
      setUsedQuestions={ setUsedQuestions }
    />        
    );

});


Then assert that we will expect "CANCEL ☓" to be the button's text.

src/components/Header/Header.test.js
it("should render with CANCEL button if started, charset selected, has questions remaining", () => {
    maxRemaining = 20;
    setCharset([]);
    setStarted(true);
    setUsedQuestions([]);
    setRemaining(maxRemaining);

    render(
    <Header
      charset={ charset }
      started={ started }
      remaining={ remaining }
      usedQuestions={ usedQuestions }
      maxRemaining={ maxRemaining }
      setStarted={ setStarted }
      setCharset={ setCharset }
      setRemaining={ setRemaining }
      setAnswer={ setAnswer }
      setResult={ setResult }
      setQuestion={ setQuestion }
      setUsedQuestions={ setUsedQuestions }
    />        
    );

    expect(screen.getByTestId("BtnStartEnd").textContent).toBe("CANCEL ☓");
});


I feel like I shouldn't have to explain this last test. It's basically a repeat of the last two, but with a different assert.

src/components/Header/Header.test.js
it("should render with RESTART button if started, charset selected, has no questions remaining", () => {
    maxRemaining = 20;
    setCharset([]);
    setStarted(true);
    setUsedQuestions([]);
    setRemaining(0);

    render(
    <Header
      charset={ charset }
      started={ started }
      remaining={ remaining }
      usedQuestions={ usedQuestions }
      maxRemaining={ maxRemaining }
      setStarted={ setStarted }
      setCharset={ setCharset }
      setRemaining={ setRemaining }
      setAnswer={ setAnswer }
      setResult={ setResult }
      setQuestion={ setQuestion }
      setUsedQuestions={ setUsedQuestions }
    />        
    );

    expect(screen.getByTestId("BtnStartEnd").textContent).toBe("RESTART ➤ ");

});    


Look at the console. You should see this!




Now let's start testing the Display component. Create Display.test.js in the Display directory, and begin with the usual imports. We also want to import the utility GetCharSet because it will be used in the testing.

src/components/Display/Display.test.js
import React from "react";
import { render, screen } from '@testing-library/react';
import Display from './Display';

import GetCharset from '../../utils/GetCharset';


Then we create the variables and their setters.

src/components/Display/Display.test.js
import React from "react";
import { render, screen } from '@testing-library/react';
import Display from './Display';

import GetCharset from '../../utils/GetCharset';

let maxRemaining;

let started;
let setStarted = (val)=> {
    started = val;
};

let charset;
let setCharset = (val)=> {
    charset = val;
};

let remaining;
let setRemaining = (val)=> {
    remaining = val;
};

let usedQuestions;
let setUsedQuestions = (val)=> {
    usedQuestions = val;
};

let answer;
let setAnswer = (val)=> {
    answer = val;
};

let result;
let setResult = (val)=> {
    result = val;
};

let question;
let setQuestion = (val)=> {
    question = val;
};


And use the describe() function, passing in the name of the component, and a callback.

src/components/Display/Display.test.js
let question;
let setQuestion = (val)=> {
    question = val;
};

describe("Display", () => {

});


There are five tests in this. The strings passed in are descriptive of the tests.

src/components/Display/Display.test.js
describe("Display", () => {
    it("should render with instructions and welcome message if not started", () => {

    });

    it("should render results if started and no questions remaining", () => {

    });    

    it("should render remaining if started and has questions remaining", () => {

    });    

    it("should render answer and tick if correct", () => {

    });    

    it("should render answer and cross if incorrect", () => {

    });    

});


Just to save you some time, each of these tests will render the Display component, with the same attributes. It's the values of the attributes that will vary.

src/components/Display/Display.test.js
describe("Display", () => {
    it("should render with instructions and welcome message if not started", () => {
            render(
            <Display
              charset={ charset }
              started={ started }
              remaining={ remaining }
              maxRemaining={ maxRemaining }
              answer={ answer }
              question={ question }
              usedQuestions={ usedQuestions }
              result={ result }
              setStarted={ setStarted }
              setRemaining={ setRemaining }
              setAnswer={ setAnswer }
              setQuestion={ setQuestion }
              setUsedQuestions={ setUsedQuestions }
            />
            );

    });

    it("should render results if started and no questions remaining", () => {
            render(
            <Display
              charset={ charset }
              started={ started }
              remaining={ remaining }
              maxRemaining={ maxRemaining }
              answer={ answer }
              question={ question }
              usedQuestions={ usedQuestions }
              result={ result }
              setStarted={ setStarted }
              setRemaining={ setRemaining }
              setAnswer={ setAnswer }
              setQuestion={ setQuestion }
              setUsedQuestions={ setUsedQuestions }
            />
            );

    });    

    it("should render remaining if started and has questions remaining", () => {
            render(
            <Display
              charset={ charset }
              started={ started }
              remaining={ remaining }
              maxRemaining={ maxRemaining }
              answer={ answer }
              question={ question }
              usedQuestions={ usedQuestions }
              result={ result }
              setStarted={ setStarted }
              setRemaining={ setRemaining }
              setAnswer={ setAnswer }
              setQuestion={ setQuestion }
              setUsedQuestions={ setUsedQuestions }
            />
            );

    });    

    it("should render answer and tick if correct", () => {
            render(
            <Display
              charset={ charset }
              started={ started }
              remaining={ remaining }
              maxRemaining={ maxRemaining }
              answer={ answer }
              question={ question }
              usedQuestions={ usedQuestions }
              result={ result }
              setStarted={ setStarted }
              setRemaining={ setRemaining }
              setAnswer={ setAnswer }
              setQuestion={ setQuestion }
              setUsedQuestions={ setUsedQuestions }
            />
            );

    });    

    it("should render answer and cross if incorrect", () => {
            render(
            <Display
              charset={ charset }
              started={ started }
              remaining={ remaining }
              maxRemaining={ maxRemaining }
              answer={ answer }
              question={ question }
              usedQuestions={ usedQuestions }
              result={ result }
              setStarted={ setStarted }
              setRemaining={ setRemaining }
              setAnswer={ setAnswer }
              setQuestion={ setQuestion }
              setUsedQuestions={ setUsedQuestions }
            />
            );

    });    
});


For the first test, we need started to be false. The rest doesn't really matter, but for the sake of neatness, we will set the others. And at the end of this test, we assert that "Welcome to J-Trainer!" is part of the document.

src/components/Display/Display.test.js
it("should render with instructions and welcome message if not started", () => {
    maxRemaining = 20;
    setCharset(null);
    setStarted(false);
    setUsedQuestions([]);
    setRemaining(maxRemaining);

        
    render(
    <Display
      charset={ charset }
      started={ started }
      remaining={ remaining }
      maxRemaining={ maxRemaining }
      answer={ answer }
      question={ question }
      usedQuestions={ usedQuestions }
      result={ result }
      setStarted={ setStarted }
      setRemaining={ setRemaining }
      setAnswer={ setAnswer }
      setQuestion={ setQuestion }
      setUsedQuestions={ setUsedQuestions }
    />
    );
    
    expect(screen.queryByText("Welcome to J-Trainer!")).toBeInTheDocument();
});


For the next test, started should be true and we should set remaining to 0. Now we set result to 1 as well. At the end, we should assert that the string "Practice more..." appears because 1 is a very poor result. And also we assert that result and maxRemaining will appear in the document in the string pattern specified.

src/components/Display/Display.test.js
it("should render results if started and no questions remaining", () => {
    maxRemaining = 20;
    setCharset(GetCharset("hiragana"));
    setStarted(true);
    setUsedQuestions([]);
    setRemaining(0);
    setResult(1);


    render(
    <Display
      charset={ charset }
      started={ started }
      remaining={ remaining }
      maxRemaining={ maxRemaining }
      answer={ answer }
      question={ question }
      usedQuestions={ usedQuestions }
      result={ result }
      setStarted={ setStarted }
      setRemaining={ setRemaining }
      setAnswer={ setAnswer }
      setQuestion={ setQuestion }
      setUsedQuestions={ setUsedQuestions }
    />
    );
    
    expect(screen.queryByText("Practice more...")).toBeInTheDocument();
    expect(screen.queryByText(result + " / " + maxRemaining)).toBeInTheDocument(); 
   
});


For this test, we set started to true and make sure that remaining is greater than 0. In this case, we use 19. We assert that the button will show 1 less than remaining, which is 18.

Also, we use the character set for Hiragana. For that, we use GetCharset(). We set question to an integer (use 0 because that's safe enough). So the char property of the element in charset pointed to by question should appear in the document.

src/components/Display/Display.test.js
it("should render remaining if started and has questions remaining", () => {
    maxRemaining = 20;
    setCharset(GetCharset("hiragana"));
    setStarted(true);
    setUsedQuestions([]);
    setRemaining(19);
    setResult(1);
    setQuestion(0);

        
    render(
    <Display
      charset={ charset }
      started={ started }
      remaining={ remaining }
      maxRemaining={ maxRemaining }
      answer={ answer }
      question={ question }
      usedQuestions={ usedQuestions }
      result={ result }
      setStarted={ setStarted }
      setRemaining={ setRemaining }
      setAnswer={ setAnswer }
      setQuestion={ setQuestion }
      setUsedQuestions={ setUsedQuestions }
    />
    );
    
    expect(screen.getByTestId("BtnRemaining").textContent).toBe("18 REMAINING ➤");
    expect(screen.queryByText(charset[question].char)).toBeInTheDocument();    

});


And we want to make sure "btnRemaining" is added as a testing id.

src/components/Display.js

if (started && remaining > 0 && charset[question] !== undefined) {
    return (
        <>
            <div className="Character">
                { charset[question].char }
            </div>
            <div className={ answer === "" ? "Result Hide" : "Result"}>
                <span className={ charset[question].romaji === answer ? "Correct" : "Wrong" }>
                    { charset[question].romaji === answer ? "✓" : "✗" }
                </span>
                { answer }
            </div>
            <div className="Remaining">
                <button data-testid="BtnRemaining" onClick={ ()=>{BtnNext_click();}} disabled={answer === ""}>
                    { remaining - 1 } REMAINING ➤
                </button>
            </div>
        </>           
    );
}


Now for this next test, we use Hiragana again. Set question to 0. And set answer to be the romaji property of the first element (index 0) of charset. And assert that answer will appear in the document, and since it is the correct answer, we display the "✓".

src/components/Display/Display.test.js
it("should render answer and tick if correct", () => {
    maxRemaining = 20;
    setCharset(GetCharset("hiragana"));
    setStarted(true);
    setUsedQuestions([]);
    setRemaining(19);
    setResult(1);
    setQuestion(0);
    setAnswer(charset[0].romaji);


    render(
    <Display
      charset={ charset }
      started={ started }
      remaining={ remaining }
      maxRemaining={ maxRemaining }
      answer={ answer }
      question={ question }
      usedQuestions={ usedQuestions }
      result={ result }
      setStarted={ setStarted }
      setRemaining={ setRemaining }
      setAnswer={ setAnswer }
      setQuestion={ setQuestion }
      setUsedQuestions={ setUsedQuestions }
    />
    );
    
    expect(screen.queryByText(answer)).toBeInTheDocument();
    expect(screen.queryByText("✓")).toBeInTheDocument();    

});


And here we have the opposite of the previous test. The variables are the same for the previous test, except that answer will be the romaji property of the second element (index 1) of the charset array, which is blatantly incorrect since question is set to 0. Thus, we assert that "✗" will appear in the document.

src/components/Display/Display.test.js
it("should render answer and cross if incorrect", () => {
    maxRemaining = 20;
    setCharset(GetCharset("hiragana"));
    setStarted(true);
    setUsedQuestions([]);
    setRemaining(19);
    setResult(1);
    setQuestion(0);
    setAnswer(charset[1].romaji);


    render(
    <Display
      charset={ charset }
      started={ started }
      remaining={ remaining }
      maxRemaining={ maxRemaining }
      answer={ answer }
      question={ question }
      usedQuestions={ usedQuestions }
      result={ result }
      setStarted={ setStarted }
      setRemaining={ setRemaining }
      setAnswer={ setAnswer }
      setQuestion={ setQuestion }
      setUsedQuestions={ setUsedQuestions }
    />
    );
    
    expect(screen.queryByText(answer)).toBeInTheDocument();
    expect(screen.queryByText("✗")).toBeInTheDocument();

});    


There you go, that's what the testing suite should show!




Finally, we test the Keyboard component. For that, create Keyboard.test.js in the Keyboard directory. We begin with the usual imports and variable declarations, and because we will be making use of charset, we import GetCharset as well.

src/components/Keyboard/Keyboard.test.js
import React from "react";
import { render, screen } from '@testing-library/react';
import userEvent from "@testing-library/user-event";
import Keyboard from './Keyboard';

import GetCharset from '../../utils/GetCharset';

let result;
let setResult = (val)=> {
    result = val;
};

let started;
let setStarted = (val)=> {
    started = val;
};

let charset;
let setCharset = (val)=> {
    charset = val;
};

let remaining;
let setRemaining = (val)=> {
    remaining = val;
};

let usedQuestions;
let setUsedQuestions = (val)=> {
    usedQuestions = val;
};

let answer;
let setAnswer = (val)=> {
    answer = val;
};

let question;
let setQuestion = (val)=> {
    question = val;
};


We describe the Keyboard component test with five tests, each with a description and callback.

src/components/Keyboard/Keyboard.test.js
import React from "react";
import { render, screen } from '@testing-library/react';
import userEvent from "@testing-library/user-event";
import Keyboard from './Keyboard';

import GetCharset from '../../utils/GetCharset';

let result;
let setResult = (val)=> {
    result = val;
};

let started;
let setStarted = (val)=> {
    started = val;
};

let charset;
let setCharset = (val)=> {
    charset = val;
};

let remaining;
let setRemaining = (val)=> {
    remaining = val;
};

let usedQuestions;
let setUsedQuestions = (val)=> {
    usedQuestions = val;
};

let answer;
let setAnswer = (val)=> {
    answer = val;
};

let question;
let setQuestion = (val)=> {
    question = val;
};

describe("Keyboard", () => {
    it("should render keys if started and there are remaining questions", () => {

    });

    it("should not render keys if not started", () => {

    });

    it("should not render keys if started and there are no remaining questions", () => {

    });    

    it("should set result + 1 if key pressed correctly", () => {

    });    

    it("should set result + 0 if key pressed incorrectly", () => {

    });
});


As with the last component, we will render the component in the tests, with the requisite data.

src/components/Keyboard/Keyboard.test.js
describe("Keyboard", () => {
    it("should render keys if started and there are remaining questions", () => {
            render(
            <Keyboard
              charset={ charset }
              remaining={ remaining }
              started={ started }
              answer={ answer }
              question={ question }
              result={ result }
              setAnswer={ setAnswer }
              setResult={ setResult }
            />
            );

    });

    it("should not render keys if not started", () => {
            render(
            <Keyboard
              charset={ charset }
              remaining={ remaining }
              started={ started }
              answer={ answer }
              question={ question }
              result={ result }
              setAnswer={ setAnswer }
              setResult={ setResult }
            />
            );

    });

    it("should not render keys if started and there are no remaining questions", () => {
            render(
            <Keyboard
              charset={ charset }
              remaining={ remaining }
              started={ started }
              answer={ answer }
              question={ question }
              result={ result }
              setAnswer={ setAnswer }
              setResult={ setResult }
            />
            );

    });    

    it("should set result + 1 if key pressed correctly", () => {
            render(
            <Keyboard
              charset={ charset }
              remaining={ remaining }
              started={ started }
              answer={ answer }
              question={ question }
              result={ result }
              setAnswer={ setAnswer }
              setResult={ setResult }
            />
            );

    });    

    it("should set result + 0 if key pressed incorrectly", () => {
            render(
            <Keyboard
              charset={ charset }
              remaining={ remaining }
              started={ started }
              answer={ answer }
              question={ question }
              result={ result }
              setAnswer={ setAnswer }
              setResult={ setResult }
            />
            );

    });
});


For this test, started is set to true, remaining is set to any value above 0, and we also set charset. We then assert that the following test ids are found in the document. We'll just use "shi" and "yu", two random answers in the entire set.

src/components/Keyboard/Keyboard.test.js
it("should render keys if started and there are remaining questions", () => {
    setRemaining(1);
    setStarted(true);
    setCharset(GetCharset("hiragana"));


    render(
    <Keyboard
      charset={ charset }
      remaining={ remaining }
      started={ started }
      answer={ answer }
      question={ question }
      result={ result }
      setAnswer={ setAnswer }
      setResult={ setResult }
    />
    );
    
    expect(screen.getByTestId("btnAnswer_shi")).toBeInTheDocument();
    expect(screen.getByTestId("btnAnswer_yu")).toBeInTheDocument(); 
   
});


We need to insert these test ids. So every button in the Keyboard component will have that testing id, which is "btnAnswer_" with the answer appended.

src/components/Keyboard.js
const answers = keyItems.map((item, index) => (
    <div
        key={'romaji_' + index}
        className={item === '' ? 'Answer Hide' : ( answer === '' ? 'Answer' : 'Answer Greyed')}
        onClick={()=>{BtnAnswer_click(item);}}
        data-testid={'btnAnswer_' + item}
    >
        {item}                    
    </div>
    )
);


For this test, we test the opposite. started is set to false, remaining is set to 0 (you could set it to any value technically, but it would make no sense), and we set charset. And we will ensure that the testing ids are not in there by making sure they are null. Again, we will use "shi" and "yu", though you can pretty much use any of the romaji properties in the charset array.

src/components/Keyboard/Keyboard.test.js
it("should not render keys if not started", () => {
    setRemaining(0);
    setStarted(false);
    setCharset(GetCharset("hiragana"));


    render(
    <Keyboard
      charset={ charset }
      remaining={ remaining }
      started={ started }
      answer={ answer }
      question={ question }
      result={ result }
      setAnswer={ setAnswer }
      setResult={ setResult }
    />
    );

    expect(screen.queryByText("shi")).toBe(null);
    expect(screen.queryByText("yu")).toBe(null);

});


For this test, we also test the opposite. started is set to true, remaining is set to 0, and we set charset. And we will ensure that the testing ids are not in there by making sure they are null. Again, we will use "shi" and "yu".

src/components/Keyboard/Keyboard.test.js
it("should not render keys if started and there are no remaining questions", () => {
    setRemaining(0);
    setStarted(true);
    charset = GetCharset("hiragana");


    render(
    <Keyboard
      charset={ charset }
      remaining={ remaining }
      started={ started }
      answer={ answer }
      question={ question }
      result={ result }
      setAnswer={ setAnswer }
      setResult={ setResult }
    />
    );

    expect(screen.queryByText("shi")).toBe(null);
    expect(screen.queryByText("yu")).toBe(null);

});    

Now this test. Set started to true, set remaining to any number greater than 0, set charset, set question to 0, and set result to, say, 5. These last two values will be important. After rendering the component, simulate a click event on the "a" button. "a" is the romaji property at index 0 of charset. Then we assert answer to be "a", and result to be (5 + 1) 6.

src/components/Keyboard/Keyboard.test.js
it("should set result + 1 if key pressed correctly", () => {
    setRemaining(1);
    setStarted(true);
    setCharset(GetCharset("hiragana"));
    setQuestion(0);
    setResult(5);


    render(
    <Keyboard
      charset={ charset }
      remaining={ remaining }
      started={ started }
      answer={ answer }
      question={ question }
      result={ result }
      setAnswer={ setAnswer }
      setResult={ setResult }
    />
    );

    userEvent.click(screen.getByTestId("btnAnswer_a"));
    expect(answer).toBe("a");
    expect(result).toBe(6);

});    


And finally, this test! We do what we did before, but deliberately simulate a click event on the button "ka", which is not at index 0. Naturally, we assert that the answer is "ka". Since we've set result to 10, we assert that result should still be 10.
it("should set result + 0 if key pressed incorrectly", () => {
    setRemaining(1);
    setStarted(true);
    setCharset(GetCharset("hiragana"));
    setQuestion(0);
    setResult(10);


    render(
    <Keyboard
      charset={ charset }
      remaining={ remaining }
      started={ started }
      answer={ answer }
      question={ question }
      result={ result }
      setAnswer={ setAnswer }
      setResult={ setResult }
    />
    );

    userEvent.click(screen.getByTestId("btnAnswer_ka"));
    expect(answer).toBe("ka");
    expect(result).toBe(10);

});


Yep, and now we have a full suite!




Final words

This app was fun to write. Not so fun to explain, but it actually was useful for teaching me to read and write in Japanese, and level up in my ReactJS.

shi yu around,
T___T

No comments:

Post a Comment