Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/wimdeblauwe/testcontainers-cypress
Testcontainers module for running Cypress tests
https://github.com/wimdeblauwe/testcontainers-cypress
cypress java spring-boot testcontainers
Last synced: 6 days ago
JSON representation
Testcontainers module for running Cypress tests
- Host: GitHub
- URL: https://github.com/wimdeblauwe/testcontainers-cypress
- Owner: wimdeblauwe
- License: apache-2.0
- Created: 2019-12-27T13:30:17.000Z (almost 5 years ago)
- Default Branch: master
- Last Pushed: 2024-09-11T14:59:10.000Z (3 months ago)
- Last Synced: 2024-12-06T00:12:07.648Z (17 days ago)
- Topics: cypress, java, spring-boot, testcontainers
- Language: Java
- Homepage:
- Size: 283 KB
- Stars: 65
- Watchers: 4
- Forks: 18
- Open Issues: 5
-
Metadata Files:
- Readme: README.adoc
- License: LICENSE
Awesome Lists containing this project
README
= Cypress Testcontainer
:toc: macroimage:https://maven-badges.herokuapp.com/maven-central/io.github.wimdeblauwe/testcontainers-cypress/badge.svg["Maven Central", link="https://search.maven.org/search?q=a:testcontainers-cypress"]
toc::[]
== Goal
The goal of this project is to make it easy to start https://www.cypress.io/[Cypress] tests via https://www.testcontainers.org/[Testcontainers].
== Example usage
=== Setup Cypress
. Create `src/test/e2e` directory in your project.
. Run `npm init` in that directory. This will generate a `package.json` file.
. Run `npm install cypress --save-dev` to install Cypress as a development dependency.
. Run `npx cypress open` to start the Cypress application. It will notice that this is the first startup and add some example tests.
. Run `npm install cypress-multi-reporters mocha mochawesome --save-dev` to install Mochawesome as a test reporter. Testcontainers-cypress will
use that to parse the results of the Cypress tests.
. Update `cypress.config.js` as follows:
+
[source,js]
----
const { defineConfig } = require('cypress')module.exports = defineConfig({
e2e: {
baseUrl: 'http://localhost:8080/',
reporter: 'cypress-multi-reporters',
reporterOptions: {
configFile: 'reporter-config.json'
}
}
})
----
. Create a `reporter-config.json` file (next to `cypress.json`) and ensure it contains:
+
[source,json]
----
{
"reporterEnabled": "spec, mochawesome",
"mochawesomeReporterOptions": {
"reportDir": "cypress/reports/mochawesome",
"overwrite": false,
"html": false,
"json": true
}
}
----[TIP]
====
Add the following to your `.gitignore` to avoid accidental commits:[source]
----
node_modules
src/test/e2e/cypress/reports
src/test/e2e/cypress/videos
src/test/e2e/cypress/screenshots
----
======= Add dependency
==== Maven
Use this dependency if you use Maven:
[source,xml]
----io.github.wimdeblauwe
testcontainers-cypress
${tc-cypress.version}
test----
Add `src/test/e2e` as a test resource directory:
[source,xml]
----
...
src/test/resources
src/test/e2e
e2e
----
==== Gradle
For Gradle, use the following dependency:
[source, groovy]
----
testImplementation 'io.github.wimdeblauwe:testcontainers-cypress:${tc-cypress.version}'
----Process `src/test/e2e` as a test resource directory and copy it into `buid/resources/test/e2e`.
[source, groovy]
----
processTestResources {
from("src/test/e2e") {
exclude 'node_modules'
into("e2e")
}
}
----The default `GatherTestResultsStrategy` assumes a Maven project and therefore you need to create a custom strategy that fits the Gradle layout.
[source, java]
----
MochawesomeGatherTestResultsStrategy gradleTestResultStrategy = new MochawesomeGatherTestResultsStrategy(
FileSystems.getDefault().getPath("build", "resources", "test", "e2e", "cypress", "reports", "mochawesome"));
new CypressContainer()
.withGatherTestResultsStrategy(gradleTestResultStrategy)
----=== Usage with a @SpringBootTest
The library is not tied to Spring Boot, but I will use the example of a `@SpringBootTest`
to explain how to use it.Suppose you have a Spring Boot application that has server-side rendered templates using Thymeleaf, and
you want to write some UI tests using Cypress. We want to drive all this from a JUnit based test, so we do the following:. Have Spring Boot start the complete application in a test. This is easy using the `@SpringBootTest` annotation on a JUnit test.
. Expose the web port that was opened towards Testcontainers so that Cypress that is running in a Docker container can access
our started web application.
. Start the Docker container to run the Cypress tests.
. Wait for the tests to be done and report the results to JUnit.Start by writing the following JUnit test:
[source,java]
----
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) //<.>
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) //<.>
public class CypressEndToEndTests {@LocalServerPort //<.>
private int port;@Test
void runCypressTests() throws InterruptedException, IOException, TimeoutException {Testcontainers.exposeHostPorts(port); //<.>
try (CypressContainer container = new CypressContainer().withLocalServerPort(port)) { //<.>
container.start();
CypressTestResults testResults = container.getTestResults(); //<.>if (testResults.getNumberOfFailingTests() > 0) {
fail("There was a failure running the Cypress tests!\n\n" + testResults); //<.>
}
}
}
}
----
<.> Have Spring Boot start the full application on a random port.
<.> Tell Spring Boot to _not_ configure a test database, Because we use a real database (via Testcontainers obviously :-) ).
<.> Have Spring inject the random port that was used when starting the application.
<.> Ensures that the container will be able to access the Spring Boot application that is started via @SpringBootTest
<.> Create the `CypressContainer` and pass in the `port` so the base URL that Cypress will use is correct.
<.> Wait on the tests and get the results.
<.> Check if there have been failures in Cypress. If so, fail the test.=== JUnit 5 dynamic tests
If you are using JUnit 5, then you can use a `@TestFactory` annotated method so that it looks like there is a JUnit test
for each of the Cypress tests.[source,java]
----
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class CypressEndToEndTests {@LocalServerPort
private int port;@TestFactory // <.>
List runCypressTests() throws InterruptedException, IOException, TimeoutException {Testcontainers.exposeHostPorts(port);
try (CypressContainer container = new CypressContainer().withLocalServerPort(port)) {
container.start();
CypressTestResults testResults = container.getTestResults();return convertToJUnitDynamicTests(testResults); // <.>
}
}@NotNull
private List convertToJUnitDynamicTests(CypressTestResults testResults) {
List dynamicContainers = new ArrayList<>();
List suites = testResults.getSuites();
for (CypressTestSuite suite : suites) {
createContainerFromSuite(dynamicContainers, suite);
}
return dynamicContainers;
}private void createContainerFromSuite(List dynamicContainers, CypressTestSuite suite) {
List dynamicTests = new ArrayList<>();
for (CypressTest test : suite.getTests()) {
dynamicTests.add(DynamicTest.dynamicTest(test.getDescription(), () -> {
if (!test.isSuccess()) {
LOGGER.error(test.getErrorMessage());
LOGGER.error(test.getStackTrace());
}
assertTrue(test.isSuccess());
}));
}
dynamicContainers.add(DynamicContainer.dynamicContainer(suite.getTitle(), dynamicTests));
}
}
----
<.> Use the `@TestFactory` annotated as opposed to the `@Test` method
<.> Use the `CypressTestResults` to generate `DynamicTest` and `DynamicContainer` instancesIf the Cypress tests look like this:
[source,javascript]
----
context('Todo tests', () => {
it('should show a message if there are no todo items', () => {
cy.request('POST', '/api/integration-test/clear-all-todos');
cy.visit('/todos');
cy.get('h1').contains('TODO list');
cy.get('#empty-todos-message').contains('There are no todo items');
});it('should show all todo items', () => {
cy.request('POST', '/api/integration-test/prepare-todo-list-items');
cy.visit('/todos');
cy.get('h1').contains('TODO list');
cy.get('#todo-items-list')
.children()
.should('have.length', 2)
.should('contain', 'Add Cypress tests')
.and('contain', 'Write blog post');
})
});
----Then running the JUnit test will show this in the IDE:
image::Cypress tests in JUnit with IntelliJ.png[]
This makes it a lot easier to see which Cypress test has failed.
== Configuration options
The `CypressContainer` instance can be customized with the following options:
[cols="m,a,m"]
|===
|Method |Description |Default|CypressContainer(String dockerImageName)
|Allows to specify the docker image to use
|cypress/included:4.0.1|withLocalServerPort(int port)
|Set the port where the server is running on. It will use http://host.testcontainers.internal as hostname with the given port as the Cypress base URL. For a `@SpringBootTest`, pass the injected `@LocalServerPort` here.
|8080|withBaseUrl(String baseUrl)
|Set the full server url that will be used as base URL for Cypress.
|http://host.testcontainers.internal:8080|withBrowser(String browser)
|Set the browser to use when running the tests (E.g. `electron`, `chrome`, `firefox`)
|electron|withSpec(String spec)
|Sets the test(s) to run. This can be a single test (e.g. `cypress/integration/todos.spec.js`)
or multiple (e.g. `cypress/integration/login/**`)
| By default (meaning not calling this method), all tests are run.|withRecord()
|Passes the `--record` flag on the command line to record the test results on the https://docs.cypress.io/guides/dashboard/introduction.html[Cypress Dashboard].
The `CYPRESS_RECORD_KEY` environment variable needs to be set for this to work.
| Not enabled by default|withRecord(String recordKey)
|Passes the `--record` flag on the command line to record the test results on the https://docs.cypress.io/guides/dashboard/introduction.html[Cypress Dashboard] using the given record key.
| Not enabled by default|withClasspathResourcePath(String resourcePath)
|Set the relative path of where the cypress tests are (the path is the location of where the `cypress.json` file is)
|e2e|withMaximumTotalTestDuration(Duration duration)
|Set the maximum timeout for running the Cypress tests.
|Duration.ofMinutes(10)|withGatherTestResultsStrategy(GatherTestResultsStrategy strategy)
|Set the `GatherTestResultsStrategy` object that should be used for gathering information on the Cypress tests results.
|MochawesomeGatherTestResultsStrategy|withMochawesomeReportsAt(Path path)
|Set the path (relative to the root of the project) where the Mochawesome reports are put.
|FileSystems.getDefault().getPath("target", "test-classes", "e2e", "cypress", "reports", "mochawesome")|withAutoCleanReports(boolean autoCleanReports)
|Set if the Cypress test reports should be automatically cleaned before each run or not.
|true
|===== Testcontainers & Cypress versions compatibility
|===
|Testcontainers-cypress |Testcontainers | Cypress|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-1.9.1[1.9.1]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.19.8[1.19.8]
|https://docs.cypress.io/guides/references/changelog.html#13-14-2[13.14.2]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-1.9.0[1.9.0]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.19.1[1.19.1]
|https://docs.cypress.io/guides/references/changelog.html#13-3-0[13.3.0]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-1.8.0[1.8.0]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.17.6[1.17.6]
|https://docs.cypress.io/guides/references/changelog.html#12-9-0[12.9.0]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-1.7.1[1.7.1]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.17.5[1.17.5]
|https://docs.cypress.io/guides/references/changelog.html#10-11-0[10.11.0]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-1.7.0[1.7.0]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.17.3[1.17.3]
|https://docs.cypress.io/guides/references/changelog.html#10-7-0[10.7.0]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-1.6.3[1.6.3]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.17.3[1.17.3]
|https://docs.cypress.io/guides/references/changelog.html#9-7-0[9.7.0]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-1.6.2[1.6.2]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.16.3[1.16.3]
|https://docs.cypress.io/guides/references/changelog.html#9-1-0[9.1.0]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-1.6.1[1.6.1]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.16.2[1.16.2]
|https://docs.cypress.io/guides/references/changelog.html#9-1-0[9.1.0]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-1.6.0[1.6.0]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.16.2[1.16.2]
|https://docs.cypress.io/guides/references/changelog.html#9-1-0[9.1.0]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-1.5.0[1.5.0]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.16.2[1.16.2]
|https://docs.cypress.io/guides/references/changelog.html#8-7-0[8.7.0]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-1.4.0[1.4.0]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.16.2[1.16.2]
|https://docs.cypress.io/guides/references/changelog.html#7-7-0[7.7.0]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-1.3.0[1.3.0]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.15.2[1.15.2]
|https://docs.cypress.io/guides/references/changelog.html#6-8-0[6.8.0]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-1.2.1[1.2.1]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.15.1[1.15.1]
|https://docs.cypress.io/guides/references/changelog.html#5-6-0[5.6.0]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-1.2.0[1.2.0]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.15.0[1.15.0]
|https://docs.cypress.io/guides/references/changelog.html#5-6-0[5.6.0]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-1.1.0[1.1.0]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.15.0[1.15.0]
|https://docs.cypress.io/guides/references/changelog.html#5-5-0[5.5.0]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-1.0.0[1.0.0]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.14.3[1.14.3]
|https://docs.cypress.io/guides/references/changelog.html#4-12-1[4.12.1]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-0.7.0[0.7.0]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.14.1[1.14.1]
|https://docs.cypress.io/guides/references/changelog.html#4-5-0[4.5.0]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-0.6.0[0.6.0]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.13.0[1.13.0]
|https://docs.cypress.io/guides/references/changelog.html#4-3-0[4.3.0]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-0.5.0[0.5.0]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.12.5[1.12.5]
|https://docs.cypress.io/guides/references/changelog.html#4-0-2[4.0.2]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-0.4.0[0.4.0]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.12.5[1.12.5]
|https://docs.cypress.io/guides/references/changelog.html#4-0-1[4.0.1]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-0.3.0[0.3.0]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.12.3[1.12.3]
|https://docs.cypress.io/guides/references/changelog.html#3-8-3[3.8.3]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-0.2.0[0.2.0]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.12.3[1.12.3]
|https://docs.cypress.io/guides/references/changelog.html#3-8-1[3.8.1]|https://github.com/wimdeblauwe/testcontainers-cypress/releases/tag/testcontainers-cypress-0.1.0[0.1.0]
|https://github.com/testcontainers/testcontainers-java/releases/tag/1.12.3[1.12.3]
|https://docs.cypress.io/guides/references/changelog.html#3-8-0[3.8.0]
|===== Troubleshooting
When running on a mac with an M1 or M2 chip, only the _electron_ browser is included in the underlying https://hub.docker.com/r/cypress/included/[cypress image] this project uses. For more info please read https://github.com/cypress-io/cypress-docker-images/issues/695[this].
There is a workaround, however, which involves following steps:
1. install rosetta 2: `softwareupdate --install-rosetta`
2. Enable rosetta emulation in *docker desktop for mac*:
- General > Use virtualization framework
- Features in Development > Use rosetta for x86/amd64 simulation on apple silicon
3. Pull the *platform specific (linux/amd64) image* for the cypress-included which you are using. For example: docker pull --platform linux/amd64 cypress/included:13.3.0== Links
Links to blog or articles that cover testcontainers-cypress:
https://www.wimdeblauwe.com/blog/2020/2020-02-01-example-usage-of-testcontainers-cypress/[Example usage of testcontainers cypress] :: Good introduction on how to get started.
https://www.wimdeblauwe.com/blog/2020/2020-02-11-testcontainers-cypress-release-0.4.0/[Testcontainers-cypress release 0.4.0] :: Shows how to run tests on multiple browsers with JUnit== Development
* Builds are done with GitHub Actions: https://github.com/wimdeblauwe/testcontainers-cypress/actions
* Code quality is available via SonarQube: https://sonarcloud.io/dashboard?id=io.github.wimdeblauwe%3Atestcontainers-cypress== Deployment
* SNAPSHOT versions are put on https://oss.sonatype.org/content/repositories/snapshots
* All releases can be downloaded from https://oss.sonatype.org/content/groups/public== Release
To release a new version of the project, follow these steps:
1. Update `pom.xml` with the new version (Use `mvn versions:set -DgenerateBackupPoms=false -DnewVersion=`)
2. Commit the changes locally.
3. Tag the commit with the version (e.g. `1.0.0`) and push the tag.
4. Create a new release in GitHub via https://github.com/wimdeblauwe/testcontainers-cypress/releases/new
- Select the newly pushed tag
- Update the release notes. This should automatically start
the [release action](https://github.com/wimdeblauwe/testcontainers-cypress/actions).
5. Update `pom.xml` again with the next `SNAPSHOT` version.
6. Close the milestone in the GitHub issue tracker.