Commit 95303e70 authored by BryceLTaylor's avatar BryceLTaylor

Add initial cypress tests

parent 91c67568
## Cypress tests
### What is this?
Cypress is an end to end testing tool that we are using to do integration tests on Scratch.
It behaves in some ways like the selenium tests that we had, but it is simpler to implement and easier to read and includes features that make debugging easier. Another advantage is that it is easier to install and get working.
### Install cypress
To install in the command line you'll need npm installed. From this folder run:
`npm install`
If you would like to install it outside of this project run this:
`npm install cypress --save-dev`
Cypress also has a gui client. To get the gui you can download it from cypress.io
### Run tests
To run all of the tests in chrome from the command line, enter `npm run test-all`. To run headless enter `npm run test-all-headless`. This will run through all of the tests in the smoke-tests folder.
To run tests directly, without using npm, enter `./node_modules/.bin/cypress run`.
### Run a single test file
Append `-s ./path/to/test/file` (or `-spec ./path/to/test/file`) to the command to run just that one suite of tests. If using `npm run` you must add an add an additional `--` before the arguments in order to pass them in:
`npm run test-all -- -s ./cypress/smoke-tests/the-test-I-want-to-run``
### Supported Browsers
Currently it defaults to running headless in Electron but it also supports Chrome.
Add `--browser chrome` to the command line when running the tests to run in chrome.
Firefox is not yet supported as of March 2018 but they are working on it.
### Environment variables
To pass in environment variables, such as USERNAME and PASSWORD for a test user you add them before calling cypress run by adding CYPRESS_ before the variable name.
It will look like this: `CYPRESS_USERNAME=madeUpName`
Alternatively you can add to the command `--env USERNAME=madeUpName`, but this is not preferred. If following `npm run` you must add an aditional `--` before adding arguments similar to how it is described in Run a single test (above).
### configuration (cypress.json)
Cypress uses a configuration file `./cypress.json` which contains environment variables and other information.
To access any variable you put in the configuration file from within your test code type `Cypress.config('property_you_want')`.
There is a special case for accessing environment variables stored in the `env : {}` object: `Cypress.env('environment_variable_you_want')` This is also how you access any environment variables passed in from the command line.
### more configuration (cypress.env.json)
You can add configuration or environment variables in the same way listed above to another json file called `cypress.env.json`. This file will overwrite whatever is in `cypress.json`. This file is untracked in git, so is useful for information that you don't want shared, such as username and password environment variables.
### Base URL
Cypress hates it when you use a base url as an environment variable. If you try it gives strange results. The base URL is set in `cypress.json` as its own variable `"baseUrl" : "https://scratch.ly"`.
This is automatically appended to `visit()` command arguments which are used to load webpages. It appends it, so you need to include a string as an argument so you would have to write it as `visit("")` or `visit("/")`.
To overwrite the baseUrl variable from the command line you need to change it just like it is an environment variable (above): `CYPRESS_baseUrl=https://scratch.mit.ed`.
Alternatively you could change it like this after calling cypress : `--config baseUrl=https://scratch.mit.edu`
### .only
If you would like to only run one test in a file you can change `it(...)` to `it.only(...)` and it will run just that one test.
Similarly you can run a collection of tests from a file by adding `.only` to a `describe(...)` function so it looks like this: `describe.only(...)`. This will run all tests in that collection and no others.
ONLY USE ONE ONLY
If you use more than one `.only` anywhere in the file it will give you unpredictable results. This includes if you put one on a collection and one on an individual test.
### .skip
If you would like to skip a test in a file you can cahnge the `it(...)` to `it.skip(...)` similarly to how you use only (above).
Skip can be used on individual tests and on suites:
`describe.skip(...)`
### Cookies
By default Cypress deletes all cookies between tests. This means that if you want to remain signed in you must manually keep the session data cookie by including this code in a beforeEach() function:
`Cypress.Cookies.preserveOnce('scratchsessionsid')`
### The GUI
The gui, which can be downloaded at cypress.io, is useful especially if you want to look back through the state of tests after they have been run. If you run in chrome from the command line the browser closes at the end of the tests.
The gui captures the state of the DOM at each step of each test. You can mouse over a step and it will show you want was happening at that time. If you click on the step you can even inspect elements, which is useful for debugging.
{
"baseUrl" : "https://scratch.ly",
"chromeWebSecurity" : false,
"integrationFolder" : "./cypress/smoke-tests",
"env": {
"USERNAME" : " ",
"PASSWORD" : " "
}
}
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}
const baseUrl = Cypress.config('baseUrl');
Cypress.on('uncaught:exception', (err, runnable) => {
return false;
});
describe('test About links in footer', function () {
beforeEach(function(){
cy.visit('/');
});
after(function(){
//this is here to fix the problem with the statistics page causing
//the next test to fail. Since it is a before each it makes the rest
//of all the tests fail. If it happens in an after, the beforeEach is fine
cy.visit('/');
});
it('click About Scratch', function(){
cy
.get('.lists :first-child :nth-child(2) :first-child :first-child')
.click();
cy
.url()
.should('eq', baseUrl + '/about');
});
it('click For Parents', function(){
cy
.get('.lists :first-child :nth-child(3) :first-child :first-child')
.click();
cy
.url()
.should('eq', baseUrl + '/parents/');
});
it('click For Educators', function(){
cy
.get('.lists :first-child :nth-child(4) :first-child :first-child')
.click()
cy
.url()
.should('eq', baseUrl + '/educators');
});
it('click For Developers', function(){
cy
.get('.lists :first-child :nth-child(5) :first-child :first-child')
.click()
cy
.url()
.should('eq', baseUrl + '/developers');
});
it('click Credits', function(){
cy
.get('.lists :first-child :nth-child(6) :first-child :first-child')
.click()
cy
.url()
.should('eq', baseUrl + '/info/credits');
});
it('click Jobs', function(){
cy
.get('.lists :first-child :nth-child(7) :first-child :first-child')
.click()
cy
.url()
.should('eq', baseUrl + '/jobs');
});
it('click Press', function(){
cy
.get('.lists :first-child :nth-child(8) :first-child :first-child')
.click()
cy
.url()
.should('match', /https:\/\/www\.scratchfoundation\.org\/media-kit\/?$/);
});
});
describe('test Community links in footer', function () {
beforeEach(function(){
cy.visit('/');
});
after(function(){
cy.visit('/');
});
it('click Community Guidelines', function(){
cy
.get('.lists :nth-child(2) :nth-child(2) :first-child :first-child')
.click();
cy
.url()
.should('eq', baseUrl + '/community_guidelines');
});
it('click Discussion Forums', function(){
cy
.get('.lists :nth-child(2) :nth-child(3) :first-child :first-child')
.click();
cy
.url()
.should('eq', baseUrl + '/discuss/');
});
it('click Scratch Wiki', function(){
cy
.get('.lists :nth-child(2) :nth-child(4) :first-child :first-child')
.click();
cy
.url()
.should('match', /https:\/\/wiki\.scratch\.mit\.edu\/wiki\/Scratch_Wiki_Home\/?$/);
});
it('click Statistics', function(){
cy
.get('.lists :nth-child(2) :nth-child(5) :first-child :first-child')
.click();
cy
.url()
.should('eq', baseUrl + '/statistics/');
});
});
describe('test Support links in footer', function () {
beforeEach(function(){
cy.visit('/');
});
after(function(){
cy.visit('/');
});
it('click Tips', function(){
cy
.get('.lists :nth-child(3) :nth-child(2) :first-child :first-child')
.click();
cy
.url()
.should('eq', baseUrl + '/tips');
});
it('click For FAQ', function(){
cy
.get('.lists :nth-child(3) :nth-child(3) :first-child :first-child')
.click();
cy
.url()
.should('eq', baseUrl + '/info/faq');
});
it('click Offline Editor', function(){
cy
.get('.lists :nth-child(3) :nth-child(4) :first-child :first-child')
.click()
cy
.url()
.should('eq', baseUrl + '/download');
});
it('click Contact Us', function(){
cy
.get('.lists :nth-child(3) :nth-child(5) :first-child :first-child')
.click()
cy
.url()
.should('eq', baseUrl + '/contact-us/');
});
it('click Scratch Store', function(){
cy
.get('.lists :nth-child(3) :nth-child(6) :first-child :first-child')
.click()
cy
.url()
.should('match', /^https:\/\/scratch-foundation\.myshopify\.com\/?$/);
});
it('click Donate', function(){
cy
.get('.lists :nth-child(3) :nth-child(7) :first-child :first-child')
.click()
cy
.url()
.should('match', /^https:\/\/secure\.donationpay\.org\/scratchfoundation\/?/);
});
});
describe('test Legal links in footer', function () {
beforeEach(function(){
cy.visit('/');
});
after(function(){
cy.visit('/');
});
it('click Terms of Use', function(){
cy
.get('.lists :nth-child(4) :nth-child(2) :first-child :first-child')
.click();
cy
.url()
.should('eq', baseUrl + '/terms_of_use');
});
it('click For Privacy Policy', function(){
cy
.get('.lists :nth-child(4) :nth-child(3) :first-child :first-child')
.click();
cy
.url()
.should('eq', baseUrl + '/privacy_policy');
});
it('click DMCA', function(){
cy
.get('.lists :nth-child(4) :nth-child(4) :first-child :first-child')
.click()
cy
.url()
.should('eq', baseUrl + '/DMCA');
});
});
describe('test Scratch Family links in footer', function () {
beforeEach(function(){
cy.visit('/');
});
it('click ScratchEd', function(){
cy
.get('.lists :nth-child(5) :nth-child(2) a')
.click();
cy
.url()
.should('match', /^http:\/\/scratched\.gse\.harvard\.edu\/?$/);
});
it('click For ScratchJr', function(){
cy
.get('.lists :nth-child(5) :nth-child(3) a')
.click();
cy
.url()
.should('match', /^http:\/\/www\.scratchjr\.org\/?$/);
});
it.skip('click Scratch Day', function(){
cy
.get('.lists :nth-child(5) :nth-child(4) a')
.click()
cy
.url()
.should('match', /^https:\/\/day\.scratch\.mit\.edu\/?$/);
});
it('click Scratch Conference', function(){
cy
.get('.lists :nth-child(5) :nth-child(5) :first-child :first-child')
.click()
cy
.url()
.should('eq', baseUrl + '/conference');
});
it('click Scratch Foundation', function(){
cy
.get('.lists :nth-child(5) :nth-child(6) :first-child :first-child')
.click()
cy
.url()
.should('match', /^https:\/\/www\.scratchfoundation\.org\/?$/);
});
});
const baseUrl = Cypress.config('baseUrl');
const username = Cypress.env('USERNAME');
const password = Cypress.env('PASSWORD');
describe('test links in nav bar while signed out', function(){
beforeEach(function (){
cy.visit('');
});
it('click SCRATCH', function(){
cy
.get('.logo')
.click();
cy
.url()
.should('eq', baseUrl + '/');
});
it('click Create', function(){
cy
.get('.link.create')
.click();
cy
.url()
.should('eq', baseUrl + '/projects/editor/?tip_bar=home')
});
it('click Explore', function(){
cy
.get('.link.explore')
.click();
cy
.url()
.should('eq', baseUrl + '/explore/projects/all');
});
it('click Tips', function(){
cy
.get('.link.tips')
.click();
cy
.url()
.should('eq', baseUrl + '/tips');
});
it('click About', function(){
cy
.get('.link.about')
.click();
cy
.url()
.should('eq', baseUrl + '/about');
});
it('submit empty Search', function(){
cy
.get('.search .form')
.submit();
cy
.url()
.should('eq', baseUrl + '/search/projects?q=');
});
it('click Join Scratch', function(){
cy
.get('.link.right.join')
.click();
cy
.get('.modal-content-iframe.mod-registration')
.should('be.visible');
});
it('click Sign In', function(){
cy
.get('.link.right.login-item')
.click()
cy
.get('.login')
.should('be.visible');
});
});
describe('test links in nav bar while signed in', function(){
before(function(){
cy
.visit('');
cy
.get('.link.right.login-item')
.click();
cy
.get('#frc-username-1088')
.type(username);
cy
.get('#frc-password-1088')
.type(password);
cy
.get('.button.submit-button.white')
.click();
cy
.get('.profile-name')
.should('be.visible');
cy
.visit('');
});
beforeEach(function(){
Cypress.Cookies.preserveOnce('scratchsessionsid');
cy
.visit('');
});
it('click SCRATCH', function(){
cy
.get('.logo')
.click();
cy
.url()
.should('eq', baseUrl + '/');
});
it('click Create', function(){
cy
.get('.link.create')
.click();
cy
.get('.container')
.should('be.visible');
});
it('click Explore', function(){
cy
.get('.link.explore')
.click();
cy
.url()
.should('eq', baseUrl + '/explore/projects/all');
});
it('click Tips', function(){
cy
.get('.link.tips')
.click();
cy
.url()
.should('eq', baseUrl + '/tips');
});
it('click About', function(){
cy
.get('.link.about')
.click();
cy
.url()
.should('eq', baseUrl + '/about');
});
it('submit empty Search', function(){
cy
.get('.search .form')
.submit();
cy
.url()
.should('eq', baseUrl + '/search/projects?q=');
});
it('click Messages', function(){
cy
.get('.link.right.messages')
.click();
cy
.url()
.should('eq', baseUrl + '/messages/');
});
it('click My Stuff', function(){
cy
.get('.link.right.mystuff')
.click();
cy
.url()
.should('eq', baseUrl + '/mystuff/');
})
});
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add("login", (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This is will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')
{
"scripts": {
"test-all": "cypress run --browser chrome",
"test-all-headless": "cypress run"
},
"devDependencies": {
"cypress": "^2.1.0"
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment