[Workshop for beginners] Let's do everything from app publishing to CI / CD + E2E test automation with Cloud9 + React + TypeScript + Amplify + Cypress! I wrote an article to experience the whole process from application release to CI / CD and E2E testing. This time, I made a tutorial to quickly experience the process of gradually growing E2E tests while developing an application. The content is designed so that you can try it in about an hour!
We use AWS Cloud9, a cloud-based integrated development environment (IDE). We will build an environment where Docker Compose can run on Cloud9. Cypress is installed when Docker is built, so you don't need to install npm commands.
If you haven't acquired an AWS account yet, please refer to the official AWS account creation flow. Please have an account.
Since Docker is built in order to proceed with the workshop, there will be insufficient space in the process of executing the build. We recommend that you expand the volume in advance by referring to this article. I increased it to 10GB-> 20GB with a margin. Extend the EBS volume area used by AWS Cloud9
Docker Compose Docker is included as standard, but Docker Compose is not included and must be installed. (As of 09/09/2020)
ec2-user:~/environment $ docker -v
Docker version 19.03.6-ce, build 369ce74
ec2-user:~/environment $ docker-compose -v
bash: docker-compose: command not found
Install by referring to the procedure in Official Document.
The following is the latest as of 09/09/2020.
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.27.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose -v
docker-compose version 1.27.0, build 980ec85b
Sample code that can perform E2E test with Cypress for local application using Docker is published on Github, so I will use this this time. https://github.com/cypress-io/cypress-example-docker-compose
This time, I will not involve committing to Github and CI / CD triggered by it, so I will clone the original repository without Forking the Github repository.
For https
$ git clone https://github.com/cypress-io/cypress-example-docker-compose.git
$ cd cypress-example-docker-compose
For ssh
$ git clone [email protected]:cypress-io/cypress-example-docker-compose.git
$ cd cypress-example-docker-compose
Run the build of the Docker container.
$ docker-compose build
will be executed.
$ npm run build
> [email protected] build /home/ec2-user/environment/cypress-example-docker-compose
> docker-compose build
Building web
Step 1/4 : FROM httpd:2.4
---> a6ea92c35c43
Step 2/4 : RUN echo "ServerName localhost" >> /usr/local/apache2/conf/httpd.conf
---> Using cache
---> e132eaf0b6d6
Step 3/4 : COPY index.html /usr/local/apache2/htdocs/
---> Using cache
---> a79afef5fb17
Step 4/4 : EXPOSE 80
---> Using cache
---> 0ba9c6797d6d
Successfully built 0ba9c6797d6d
Successfully tagged apache:latest
Building e2e
Step 1/7 : FROM cypress/base:10
10: Pulling from cypress/base
d6ff36c9ec48: Pull complete
c958d65b3090: Pull complete
edaf0a6b092f: Pull complete
80931cf68816: Pull complete
bc1b8aca3825: Pull complete
ad9790d89c32: Pull complete
6085b6a0249c: Pull complete
6af9e71c78d2: Pull complete
d85bae49b22d: Pull complete
f6c8ce594b00: Pull complete
d67d7860a80a: Pull complete
b3a1dfd049d1: Pull complete
6fb47a9e5454: Pull complete
Digest: sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Status: Downloaded newer image for cypress/base:10
---> 071155d6ed07
Step 2/7 : WORKDIR /app
---> Running in 468f37420452
Removing intermediate container 468f37420452
---> 2f1c6d19e291
Step 3/7 : COPY package.json .
---> 90ec115cb213
Step 4/7 : COPY package-lock.json .
---> 54e720d60a87
Step 5/7 : ENV CI=1
---> Running in 5e56a602e37c
Removing intermediate container 5e56a602e37c
---> 670f913b90e6
Step 6/7 : RUN npm ci
---> Running in d511a99685c5
> [email protected] postinstall /app/node_modules/cypress
> node index.js --exec install
[14:40:14] Downloading Cypress [started]
[14:40:17] Downloading Cypress [completed]
[14:40:17] Unzipping Cypress [started]
[14:40:33] Unzipping Cypress [completed]
[14:40:33] Finishing Installation [started]
[14:40:33] Finishing Installation [completed]
added 216 packages in 25.818s
Removing intermediate container d511a99685c5
---> 8dc49d0f8503
Step 7/7 : RUN npx cypress verify
---> Running in aa9a7fb8a0d9
[14:41:10] Verifying Cypress can run /root/.cache/Cypress/5.1.0/Cypress [started]
[14:41:14] Verifying Cypress can run /root/.cache/Cypress/5.1.0/Cypress [completed]
Removing intermediate container aa9a7fb8a0d9
---> 0a5f502ade2e
Successfully built 0a5f502ade2e
Successfully tagged cypress:latest
First, let's make sure that the test works untouched.
And let's see what makes Cypress so happy.
$ docker-compose build
will be executed.
$ npm run up
> [email protected] up /home/ec2-user/environment/cypress-example-docker-compose
> docker-compose up --abort-on-container-exit --exit-code-from e2e
Creating network "cypress-example-docker-compose_default" with the default driver
Creating apache ... done
Creating cypress ... done
Attaching to apache, cypress
apache | [Wed Sep 09 14:44:05.645451 2020] [mpm_event:notice] [pid 1:tid 140649514787968] AH00489: Apache/2.4.46 (Unix) configured -- resuming normal operations
apache | [Wed Sep 09 14:44:05.664458 2020] [core:notice] [pid 1:tid 140649514787968] AH00094: Command line: 'httpd -D FOREGROUND'
cypress |
cypress | ====================================================================================================
cypress |
cypress | (Run Starting)
cypress |
cypress | ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
cypress | │ Cypress: 5.1.0 │
cypress | │ Browser: Electron 83 (headless) │
cypress | │ Specs: 1 found (spec.js) │
cypress | └────────────────────────────────────────────────────────────────────────────────────────────────┘
cypress |
cypress |
cypress | ────────────────────────────────────────────────────────────────────────────────────────────────────
cypress |
cypress | Running: spec.js (1 of 1)
apache | 172.18.0.3 - - [09/Sep/2020:14:44:15 +0000] "GET / HTTP/1.1" 200 27
cypress |
cypress | (Results)
cypress |
cypress | ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
cypress | │ Tests: 1 │
cypress | │ Passing: 1 │
cypress | │ Failing: 0 │
cypress | │ Pending: 0 │
cypress | │ Skipped: 0 │
cypress | │ Screenshots: 0 │
cypress | │ Video: true │
cypress | │ Duration: 0 seconds │
cypress | │ Spec Ran: spec.js │
cypress | └────────────────────────────────────────────────────────────────────────────────────────────────┘
cypress |
cypress |
cypress | (Video)
cypress |
cypress | - Started processing: Compressing to 32 CRF
cypress | - Finished processing: /app/cypress/videos/spec.js.mp4 (1 second)
cypress |
cypress |
cypress | ====================================================================================================
cypress |
cypress | (Run Finished)
cypress |
cypress |
cypress | Spec Tests Passing Failing Pending Skipped
cypress | ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
cypress | │ ✔ spec.js 342ms 1 1 - - - │
cypress | └────────────────────────────────────────────────────────────────────────────────────────────────┘
cypress | ✔ All specs passed! 342ms 1 1 - - -
cypress |
cypress exited with code 0
Aborting on container exit...
Stopping apache ... done
It will take a video without permission and leave it.
Video storage location
$ ls -l e2e/cypress/videos/spec.js.mp4
-rw-r--r-- 1 root root 29169 Sep 9 14:44 e2e/cypress/videos/spec.js.mp4
When viewing videos and images on AWS Cloud9, you can view them by focusing the mouse cursor on the file as shown below, right-clicking and selecting "Preview".
With Selenium, you may insert code like page.save_screenshot'failed.png'
where it might fail and leave a screenshot.
By default, Cypress will leave a still image when the test fails without any special work.
The video will remain, so you can check it from there, but it's here! Still images are easier to understand.
The following is an example of failing to change the verification that the expected result "Hi there" is displayed to "Hey there".
$ git diff
diff --git a/e2e/cypress/integration/spec.js b/e2e/cypress/integration/spec.js
index 5e90f2d..809de14 100644
--- a/e2e/cypress/integration/spec.js
+++ b/e2e/cypress/integration/spec.js
@@ -1,4 +1,4 @@
it('loads page', () => {
cy.visit('/')
- cy.contains('Hi there')
+ cy.contains('Hey there')
})
$ npm run up
> [email protected] up /home/ec2-user/environment/cypress-example-docker-compose
> docker-compose up --abort-on-container-exit --exit-code-from e2e
Starting apache ... done
Starting cypress ... done
Attaching to apache, cypress
apache | [Wed Sep 09 14:55:49.753051 2020] [mpm_event:notice] [pid 1:tid 140399861245056] AH00489: Apache/2.4.46 (Unix) configured -- resuming normal operations
apache | [Wed Sep 09 14:55:49.753761 2020] [core:notice] [pid 1:tid 140399861245056] AH00094: Command line: 'httpd -D FOREGROUND'
cypress |
cypress | ====================================================================================================
cypress |
cypress | (Run Starting)
cypress |
cypress | ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
cypress | │ Cypress: 5.1.0 │
cypress | │ Browser: Electron 83 (headless) │
cypress | │ Specs: 1 found (spec.js) │
cypress | └────────────────────────────────────────────────────────────────────────────────────────────────┘
cypress |
cypress |
cypress | ────────────────────────────────────────────────────────────────────────────────────────────────────
cypress |
cypress | Running: spec.js (1 of 1)
apache | 172.18.0.3 - - [09/Sep/2020:14:55:59 +0000] "GET / HTTP/1.1" 200 27
cypress |
cypress | (Results)
cypress |
cypress | ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
cypress | │ Tests: 1 │
cypress | │ Passing: 0 │
cypress | │ Failing: 1 │
cypress | │ Pending: 0 │
cypress | │ Skipped: 0 │
cypress | │ Screenshots: 1 │
cypress | │ Video: true │
cypress | │ Duration: 4 seconds │
cypress | │ Spec Ran: spec.js │
cypress | └────────────────────────────────────────────────────────────────────────────────────────────────┘
cypress |
cypress |
cypress | (Screenshots)
cypress |
cypress | - /app/cypress/screenshots/spec.js/loads page (failed).png (1280x720)
cypress |
cypress |
cypress | (Video)
cypress |
cypress | - Started processing: Compressing to 32 CRF
cypress | - Finished processing: /app/cypress/videos/spec.js.mp4 (2 seconds)
cypress |
cypress |
cypress | ====================================================================================================
cypress |
cypress | (Run Finished)
cypress |
cypress |
cypress | Spec Tests Passing Failing Pending Skipped
cypress | ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
cypress | │ ✖ spec.js 00:04 1 - 1 - - │
cypress | └────────────────────────────────────────────────────────────────────────────────────────────────┘
cypress | ✖ 1 of 1 failed (100%) 00:04 1 - 1 - -
cypress |
cypress exited with code 1
Storage location for still images taken when the test fails
$ ls -l e2e/cypress/screenshots/spec.js/loads\ page\ \(failed\).png
-rw-r--r-- 1 root root 29790 Sep 9 14:56 e2e/cypress/screenshots/spec.js/loads page (failed).png
[e2e/cypress/screenshots/spec.js/loads\ page\ (failed).png ] You can see that it is "Hey there" even though you are expecting "Hi there"!
Test-Driven Development (TDD) is a test-first program development method. In other words, it refers to a method of writing test code before implementing a program and proceeding with implementation and refactoring to match the test code. Test-driven development proceeds in the order of "Red", "Green", and "Refactoring". Test-driven development has the following advantages:
Red
Green
Refactoring
Since the test code is written before the program of the function you want to implement, the test fails at first, but the program is implemented and modified many times in a short cycle to eliminate bugs, and refactoring when you can write code that works correctly to hold.
From here, feel free to think about the functional requirements and proceed with test implementation and application implementation.
Here are some examples of requirements.
Please refer to it and decide on the original specifications before proceeding.
Use HTML or CSS to implement the web page.
When writing HTML, please note that if you forget to write <meta charset =" utf-8 "/>
, Japanese characters will be garbled.
For CSS, see [Note] CSS Reintroduction-Selector-.
Create a self-introduction page. The self-introduction includes:
For those who ask, "How should I write a test for this?", I also made a command collection, so please refer to it. Cypress command collection that I want to keep this in mind
e2e/cypress/integration/spec.js
it('load page', () => {
cy.visit('/')
cy.get('.title').should('have.text', 'Rusty Nail room')
cy.get('.summary').should('have.text', 'This is Rusty Nail's self-introduction page.')
cy.get('.content__name').should('have.text', 'Rusty Nail')
cy.get('.content__age').should('have.text', '34 years old')
cy.get('.content__hobby').should('have.text', 'Table tennis')
})
Run $ npm run up
to run the test.
Of course it fails because I haven't written any tests yet.
webapp/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>Rusty Nail room</title>
</head>
<body>
<h1 class='title'>Rusty Nail room</h1>
<h2 class='summary'>This is Rusty Nail's self-introduction page.</h2>
<ul class='content'>
<li class='content__name'>Rusty Nail</li>
<li class='content__age'>34 years old</li>
<li class='content__hobby'>Table tennis</li>
</ul>
</body>
</html>
Run $ npm run build
to update the changes in webapp / index.html to the Docker image.
Run $ npm run up
again to run the test.
The test is successful because the application that meets the requirements has also been implemented.
With this kind of feeling, if you want to add "special skills", "favorite food", etc. next time, Write one test and repeat the implementation one.
In the workshop, we used the default browser, but you can specify it if various browsers are installed.
used(Default)browser
cypress | ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
cypress | │ Cypress: 5.1.0 │
cypress | │ Browser: Electron 83 (headless) │
cypress | │ Specs: 1 found (spec.js) │
cypress | └────────────────────────────────────────────────────────────────────────────────────────────────┘
In the workshop, browser installation etc. will be omitted because it will prepare the Docker environment.
You can specify the browser as follows. For details on supported browsers, see the official Launching Browsers.
Example of specifying chrome
$ cypress run --browser chrome
If you want to run headless, specify the --headless
option as follows:
$ cypress run --browser chrome --headless
Recommended Posts