Lab 07: Cypress Testing - andreaswissel/design-systems-workshop GitHub Wiki
Hint: if you got lost, you can always check out the corresponding branch for the lab. If you want to start over, you can reset it by typing executing git reset --hard origin/lab-6
So we have the documentation covered - which is a very good thing! But somehow we need to keep tabs on our components and make sure that they're actually working the way we intend them to. This is where Cypress comes into play.
- We will start by adding Cypress to the project.
Execute the following command in the Angular project:
ng add @cypress/schematic
- Answer the upcoming prompts with "Yes"
You will be prompted by the CLI:
- Answer
The package @cypress/[email protected] will be installed and executed. Would you like to proceed?
withYes
. - Answer
Would you like the default ng e2e command to use Cypress?
withYes
. - Answer
Would you like to add Cypress component testing? This will add all files needed for Cypress component testing.
withYes
.
This will add Cypress to the project and overwrite the default ng e2e
command. This is only relevant in projects that use an Angular CLI version prior to version 13.
- Run cypress with
ng e2e
After cypress has started, you should see the Cypress control panel:
In the control panel, you can see a first integration test which was generated by the Cypress setup. In the top right corner, you can select a browser which will be used to execute the tests. Select a browser of your choice!
- Run your first integration test
Click on cypress/e2e/spec.cy.ts
to execute the spec. Cypress will then open up your chosen browser and run the test.
This test will fail, but this is intended. Since our page does not contain the sentence specified in the test, it will throw an error.
- Fix the test
Open up cypress/e2e/spec.cy.ts
in your IDE and edit the contents:
describe('My First Test', () => {
it('Visits the initial project page', () => {
cy.visit('/')
cy.contains('Welcome')
- cy.contains('app is running!')
+ cy.contains('Hello, design-systems')
})
})
Once you've corrected the application name, run the test again. It should now show up as passed!
Cypress is up and running and you have already wrote a successful integration test. Look at you go! Let's move on to testing our components now.
- Run Storybook
In a separate terminal instance, run the following command:
npm run storybook
Storybook should now upen up simultaneously.
- Add a new test
We don't want things to get cluttered, so we will now add a new file for our button component tests.
Create a new file called cypress/e2e/button.cy.ts
and add the following contents:
describe("The ButtonComponent", () => {
it("Checks that the button element exists and is visible", () => {
cy.visit(
"http://localhost:6006/iframe.html?id=components-button--default-button&viewMode=story"
);
cy.get("app-button").should("exist");
cy.get("app-button").should("be.visible");
});
});
This code does three main things:
- Visit the story in Storybook
Cypress navigates the browser to the ButtonComponent story in our local Storybook instance. There's one key difference to how we usually view stories, though. The link above points to the contents of the Canvas
iframe, rather than Storybook as a whole. You can grab this link by clicking the Open canvas in new tab
button in Storybook:
- Asserts that the button exists
We tell Cypress to get a hold of the <app-button>
element and verify that it exists in the DOM.
- Asserts that the button is visible
This is different from the previous assertion, in the way that Cypress now checks if the button is actually there from a users perspective. While .should('exist')
will probably lead to the same result most of the time, there is some cases, where the result of these two tests will differ from each other. So always make sure to check both!
- Run the test
In the Cypress control panel, run your new test. Your result should look like this:
Component tests make it very easy to test components in isolation and are a fast and efficient way to write integration tests for your components. So let's add one!
- Add a file called
button.cy.ts
in your component folder
We locate this file right next to the component, since it only relates to this component and, unlike e2e test, doesn't test or touch any other parts of our application.
- Write the component test
import { ButtonComponent } from './button.component';
describe('The ButtonComponent', () => {
beforeEach(() => {
cy.mount(ButtonComponent);
});
it('checks that the button element exists and is visible', () => {
cy.get('button').should('exist');
cy.get('button').should('be.visible');
});
it('should check that the button is rendering correctly', () => {
cy.get('button').should('have.css', 'background-color', 'rgb(0, 133, 252)');
cy.get('button').should('have.css', 'border-color', 'rgb(3, 87, 163)');
});
});
This test verifies that the button exists and has the correct colors. But we learned before that component tests are mainly used for testing the behavior of a component. So let's try to add a label to the button.
- Control the label property in the component test
import { ButtonComponent } from './button.component';
describe('The ButtonComponent', () => {
beforeEach(() => {
cy.mount(ButtonComponent, {
+ componentProperties: {
+ label: 'Click Me',
+ }
});
});
it('checks that the button element exists and is visible', () => {
cy.get('button').should('exist');
cy.get('button').should('be.visible');
});
it('should check that the button is rendering correctly', () => {
cy.get('button').should('have.css', 'background-color', 'rgb(0, 133, 252)');
cy.get('button').should('have.css', 'border-color', 'rgb(3, 87, 163)');
});
+ it('should check that the button label is rendering correctly', () => {
+ cy.get('button').should('have.text', 'Click Me');
+ });
});
Hint: You need to exclude *.cy.ts
files from Storybook. You can do that by editing the .storybook/tsconfig.json
-file:
{
"extends": "../tsconfig.app.json",
"compilerOptions": {
"types": [
"node"
],
"allowSyntheticDefaultImports": true
},
"exclude": [
"../src/test.ts",
"../src/**/*.spec.ts",
+ "../src/**/*.cy.ts",
"../projects/**/*.spec.ts"
],
"include": [
"../src/**/*",
"../projects/**/*"
],
"files": [
"./typings.d.ts"
]
}
- The Cypress app should open up when running
ng e2e
- Your integration test for the ButtonComponent should correctly assert that the button is visible
Button E2E test file
cypress/e2e/button.cy.ts
describe("The ButtonComponent", () => {
it("Checks that the button element exists and is visible", () => {
const selector = "app-button";
cy.visitComponentStory("button", "default-button");
cy.get(selector).should("exist");
cy.get(selector).should("be.visible");
});
});
Button component test file
src/button/button.cy.ts
import { ButtonComponent } from './button.component';
describe('The ButtonComponent', () => {
beforeEach(() => {
cy.mount(ButtonComponent, {
componentProperties: {
label: 'Click Me',
}
});
});
it('checks that the button element exists and is visible', () => {
cy.get('button').should('exist');
cy.get('button').should('be.visible');
});
it('should check that the button is rendering correctly', () => {
cy.get('button').should('have.css', 'background-color', 'rgb(0, 133, 252)');
cy.get('button').should('have.css', 'border-color', 'rgb(3, 87, 163)');
});
it('should check that the button label is rendering correctly', () => {
cy.get('button').should('have.text', 'Click Me');
});
});