Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move cypress test project to own folder #134

Merged
merged 27 commits into from
Jul 5, 2018
Merged

Conversation

jesstelford
Copy link
Contributor

@jesstelford jesstelford commented Jun 23, 2018

I've left packages/test-project alone, but the Cypress tests now run against cypress/projects/basic.

Ideally there will be other cypress/projects/* in the future for different setups.

@dominikwilkowski
Copy link
Contributor

I was just working on this. I thought we can still use the test project but clean data via graphql queries rather than relying on the reset route... would it not cause a lot more work now that we have two test projects? Relaying on one implementation and taking charge of it's store of data would be a better outcome IMO?

@jesstelford
Copy link
Contributor Author

The main problem I'm trying to solve is completely different Keystone setups, not just data.

For example, I'll need a project where access control on everything is set to read: false, which means none of the other tests will pass.

The changes in this PR are the first step to having project(s) separate to the test-project that are run against cypress.

The biggest down side here is that the test-project will get out of sync with the projects we're testing against, but we could add a set of smoke tests to test-project to make sure it's all ok.

In terms of resetting data via GraphQL: That's a great idea, and would work really well with each of the individual projects we setup with this PR 👍

@jesstelford
Copy link
Contributor Author

Huzzah! It works:

$ CYPRESS_CACHE_FOLDER=$CIRCLE_WORKING_DIRECTORY/node_modules/cypress/.cache/ yarn cypress:run:ci
yarn run v1.6.0
$ start-server-and-test cypress:start:server http-get://localhost:3000/admin cypress:run:cmd:ci
starting server using command "npm run cypress:start:server"
and when url "http-get://localhost:3000/admin" is responding
running tests using command "cypress:run:cmd:ci"

> keystone@5.0.0 cypress:start:server /home/circleci/repo
> cd cypress/projects/basic && PORT=3000 yarn start

$ node -r dotenv-safe/config index.js
KeystoneJS 5 ready on port 3000
Connection success
ℹ 「wdm」: wait until bundle finished: /admin
ℹ 「wdm」:    533 modules
ℹ 「wdm」: Compiled successfully.

> keystone@5.0.0 cypress:run:cmd:ci /home/circleci/repo
> cypress run --env PORT=3000 --reporter junit --reporter-options "mochaFile=reports/junit/cypress-results.xml"

# ... Cypress runs

    All specs passed!                           01:11       33       33        -        -        -  

Done in 123.57s.

@@ -6,8 +6,6 @@ describe('Adding data', () => {
'ks-input-name': 'John Doe',
'ks-input-email': 'john@gmail.com',
'ks-input-password': 'password1',
'ks-input-twitterId': '@johndoe',
'ks-input-twitterUsername': 'John Doe',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I simplified the tests a bit by removing the twitter stuff since it wasn't actually under test beyond "is shown in admin UI", which is passing tests elsewhere.

package.json Outdated
"cypress:run:cmd:ci": "cypress run --env PORT=3000 --reporter junit --reporter-options \"mochaFile=reports/junit/cypress-results.xml\"",
"cypress:open": "start-server-and-test cypress:start:server http-get://localhost:3000/admin cypress:open:cmd",
"cypress:run": "start-server-and-test cypress:start:server http-get://localhost:3000/admin cypress:run:cmd",
"cypress:run:ci": "start-server-and-test cypress:start:server http-get://localhost:3000/admin cypress:run:cmd:ci",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

start-server-and-test waits for the server to be up and running before trying to run the tests, removing any timing issues with webpack compilation 👍

package.json Outdated
@@ -98,7 +103,8 @@
},
"bolt": {
"workspaces": [
"packages/*"
"packages/*",
"cypress/projects/*"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jesstelford I was thinking we would (when ready) do effectively this, but split into multiple test-project packages at some higher level and have cypress test them.

roughly:

"workspaces": [
  "packages/*",
  "projects/*",
]

This way we can have multiple test projects set up demonstrating different features / configurations / etc

Do you think it's a good idea to also split on projects used explicitly for cypress, vs. those not under test? I'm not sure about not having the other test projects not automatically tested. I worry that'll lead to them diverging, or work being done against a "main" test project that's not caught by tests, etc.

What if we did came at this the other way around? Created multiple test projects at the top level, actually included the test scripts with them (and imported from the cypress directory) so we are colocating the code currently under cypress/integration with the test project?

Not sure which of these approaches is more scalable or likely to keep us on the right track long term.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"workspaces": [
  "packages/*",
  "projects/*",
]

This way we can have multiple test projects set up demonstrating different features / configurations / etc

Great idea. Done.

Do you think it's a good idea to also split on projects used explicitly for cypress, vs. those not under test? I'm not sure about not having the other test projects not automatically tested. I worry that'll lead to them diverging, or work being done against a "main" test project that's not caught by tests, etc.

It's a great point. We should definitely have tests covering each of the projects, so they never get out of sync. I'll make sure there are at least basic tests for each.

Created multiple test projects at the top level, actually included the test scripts with them (and imported from the cypress directory)

I don't think Cypress allows this - they're oddly strict in the folder structure of where tests are located, etc. But if it's possible, it'd be great!

@jesstelford jesstelford force-pushed the cypress-projects branch 7 times, most recently from 7bec564 to 1904631 Compare June 29, 2018 05:10
@dominikwilkowski
Copy link
Contributor

Yes that's totally right. After a brief discussion with @jesstelford I think it's best to prefix each env var so that it clearly corresponds to each project. In CI as well as in the .env files.
I suggest something like:

project-basic-CLOUDINARY_CLOUD_NAME = abc
project-basic-CLOUDINARY_KEY = abc
project-basic-CLOUDINARY_SECRET = abc
project-basic-PORT = 123

project-auth-CLOUDINARY_CLOUD_NAME = abc
project-auth-CLOUDINARY_KEY = abc
project-auth-CLOUDINARY_SECRET = abc
project-auth-PORT = 123

project-twitter-CLOUDINARY_CLOUD_NAME = abc
project-twitter-CLOUDINARY_KEY = abc
project-twitter-CLOUDINARY_SECRET = abc
project-twitter-PORT = 123

Explicit over implicit and if it ever gets too verbose we can still add some magic.

@jesstelford jesstelford force-pushed the cypress-projects branch 3 times, most recently from 61a1de6 to e659c66 Compare July 4, 2018 22:01
@jesstelford
Copy link
Contributor Author

So we've gone with number 5 from above: Running cypress tests in parallel and from their project directories.

There are 2 caveats:

  1. When running locally, the output is garbage (multiple tests outputting at once).d
  2. When run on CircleCI, our account only has 1x parallelism, so while it's all setup to run in parallel, in practice it still runs serially (~5:00min vs ~2:40).

@@ -4,88 +4,116 @@
#
version: 2

x-job-setup: &job-setup
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is like a "default" config that is imported lower down in the .yml file, so we don't have to repeat ourselves.

x-job-setup: &job-setup
docker:
# specify the version you desire here
- image: circleci/node:carbon-browsers
Copy link
Contributor Author

@jesstelford jesstelford Jul 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The -browsers version removes the need for apt-get install later, reducing build time by about 22seconds per test run.

name: Login E2E tests
command: CYPRESS_CACHE_FOLDER=$CIRCLE_WORKING_DIRECTORY/node_modules/cypress/.cache/ bolt ws run cypress:run:ci --only-fs projects/login
environment:
PORT: 4000
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOTE: Thanks to running these in seperate processes, the env vars no longer clash, so prefixing is not necessary.

@@ -5,8 +5,8 @@
"license": "MIT",
"scripts": {
"coverage": "jest --coverage --collectCoverageFrom=packages/**/*.{js}",
"cypress:open": "cypress open",
"cypress:run": "cypress run",
"cypress:run": "bolt ws run cypress:run",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used only for local testing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it then rather use bolt ws run cypress:open or will this break?

@@ -1,24 +1,22 @@
describe('Adding data', () => {
[
{
url: 'http://localhost:3000/admin/users',
url: '/admin/users',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By setting the baseUrl in cypress/plugins/index.js, we don't need to specify the entire URL for cy.X commands, avoiding having to read from env vars too.

Cypress.Commands.add('graphql_query', query =>
apolloFetch({ query })
Cypress.Commands.add('graphql_query', (uri, query) =>
getApollo(uri)({ query })
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to explicitly pass in the graphql endpoint, enabling future use of querying different endpoints as required.


const GRAPHQL_URI = 'http://localhost:3000/admin/api';
const apolloFetch = createApolloFetch({ uri: GRAPHQL_URI });
const getApollo = memoize(function createApollo(uri) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only want to create a single instance per URI, so we memoize based on that param.

"prepare-test-server": "node -r dotenv-safe/config -e 'require(`execa`)(`start-server-and-test`, [`start`, `http-get://localhost:${process.env.PORT}/admin`, process.argv[1]], { stdio: `inherit` }).catch(error => { console.error(error.toString()); process.exit(error.code) })'",
"cypress:run:ci": "yarn prepare-test-server cypress:run:cmd:ci",
"cypress:run": "if [ -f .env ]; then yarn prepare-test-server cypress:run:cmd; else echo \"\nError: Must create a projects/basic/.env file.\nSee projects/basic/.env.example for values\n\"; exit 1; fi",
"cypress:open": "if [ -f .env ]; then yarn prepare-test-server cypress:open:cmd; else echo \"\nError: Must create a projects/basic/.env file.\nSee projects/basic/.env.example for values\n\"; exit 1; fi"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These commands are repeated in each project. They're of medium complexity, and favour repetition over more scripts given the feedback on the original PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note also there is a friendly error output for first time test run (when .env hasn't been setup).

@@ -8,7 +8,8 @@
"node": ">=8.4.0"
},
"scripts": {
"start": "node -r dotenv-safe/config index.js"
"start": "node -r dotenv-safe/config index.js",
"cypress:run:ci": "exit 0"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No tests setup yet for this project, so exit with success.

@jesstelford
Copy link
Contributor Author

☝️ There's some inline comments explaining things that are going on.

I recommend we do a squash and merge for this, the commits got a bit crazy :P

screen shot 2018-07-05 at 9 44 57 am

@timleslie
Copy link
Contributor

This all looks good to me. I particularly like that the integration tests are explicitly colocated with the project they test. Hopefully this pattern will be valuable to developers building their own projects.

There are two follow up tasks which we should look into after this task goes through:

  1. Provide a mechanism for running the cypress tests locally in some meaningful way (and update the top level README.md to reflect this)
  2. Invest in some more circle CI containers to allow for faster turnaround of tests. This will also give us access to the "Insights" tab in circle CI which will... give us more insights...

@jesstelford
Copy link
Contributor Author

jesstelford commented Jul 5, 2018

Invest in some more circle CI containers to allow for faster turnaround of tests. This will also give us access to the "Insights" tab in circle CI which will... give us more insights...

🤔 ... insightful!

Provide a mechanism for running the cypress tests locally in some meaningful way (and update the top level README.md to reflect this)

This mechanism already exists, just the output on the CLI is confusing (you'll still see failures though).

I'll update the README.md now.

edit @timleslie see commit 4f7aad0 for updated docs.

@dominikwilkowski
Copy link
Contributor

Looks great, LGTM

@jesstelford jesstelford merged commit 84287f2 into master Jul 5, 2018
@jesstelford jesstelford deleted the cypress-projects branch July 5, 2018 05:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants