This commit is contained in:
David Négrier 2020-04-16 22:44:31 +02:00
commit db605d100e
13 changed files with 1567 additions and 0 deletions

View File

@ -83,3 +83,20 @@ jobs:
with: with:
msg: Environment deployed at http://${{ env.GITHUB_REF_SLUG }}.workadventure.test.thecodingmachine.com msg: Environment deployed at http://${{ env.GITHUB_REF_SLUG }}.workadventure.test.thecodingmachine.com
check_for_duplicate_msg: true check_for_duplicate_msg: true
- name: Run Cypress tests
uses: cypress-io/github-action@v1
env:
CYPRESS_BASE_URL: http://${{ env.GITHUB_REF_SLUG }}.workadventure.test.thecodingmachine.com
with:
env: host=${{ env.GITHUB_REF_SLUG }}.workadventure.test.thecodingmachine.com,port=80
spec: cypress/integration/spec.js
wait-on: http://${{ env.GITHUB_REF_SLUG }}.workadventure.test.thecodingmachine.com
working-directory: e2e
- name: "Upload the screenshot on test failure"
uses: actions/upload-artifact@v1
if: failure()
with:
name: "screenshot"
path: "./e2e/cypress/screenshots/spec.js/WorkAdventureGame -- loads (failed).png"

View File

@ -65,3 +65,4 @@ jobs:
- name: "Jasmine" - name: "Jasmine"
run: yarn test run: yarn test
working-directory: "back" working-directory: "back"

20
docker-compose.ci.yml Normal file
View File

@ -0,0 +1,20 @@
version: '3'
services:
wait_app:
image: dadarek/wait-for-dependencies
depends_on:
- reverse-proxy
command: front:8080
cypress:
# the Docker image to use from https://github.com/cypress-io/cypress-docker-images
image: "cypress/included:3.8.3"
depends_on:
- reverse-proxy
environment:
# pass base url to test pointing at the web application
- CYPRESS_baseUrl=http://front:8080
working_dir: /e2e
volumes:
- ./e2e/:/e2e

View File

@ -7,6 +7,9 @@ services:
- "80:80" - "80:80"
# The Web UI (enabled by --api.insecure=true) # The Web UI (enabled by --api.insecure=true)
- "8080:8080" - "8080:8080"
depends_on:
- back
- front
volumes: volumes:
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock

3
e2e/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
screenshots/
videos/
node_modules/

36
e2e/CYPRESS.md Normal file
View File

@ -0,0 +1,36 @@
# Testing with cypress
This project use [cypress](https://www.cypress.io/) to do functional testing of the website.
Unfortunately we cannot integrate it with docker-compose for the moment, so you will need to install some packages locally on your pc.
## Getting Started
You will need to install theses dependancies on linux (don't know about mac):
```bash
sudo apt update
sudo apt install libgtk2.0-0 libgtk-3-0 libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb
```
Cypress can be installed locally in the e2e directory
```bash
cd e2e
npm install
```
How to use:
```bash
npm run cy:run
npm run cy:open
```
The first command will run all tests in the terminal, while the second will open the interactive task runner which allow you to easily manage the test workflow
[More details here](https://docs.cypress.io/guides/getting-started/testing-your-app.html#Step-1-Start-your-server)
## How to test a game
Cypress cannot "see" and so cannot directly manipulate the canva created by Phaser.
This means we have to do workarounds such as exposing core objects in the window so that cypress can manipulate them or doing console that cypress can catch.

7
e2e/cypress.json Normal file
View File

@ -0,0 +1,7 @@
{
"baseUrl": "http://workadventure.localhost",
"video": false,
"defaultCommandTimeout": 20000,
"pluginsFile": false,
"supportFile": false
}

View File

@ -0,0 +1,25 @@
Cypress.on('window:before:load', (win) => {
// because this is called before any scripts
// have loaded - the ga function is undefined
// so we need to create it.
win.cypressAsserter = cy.stub().as('ca')
})
describe('WorkAdventureGame', () => {
beforeEach(() => {
cy.visit('/', {
onBeforeLoad (win) {
cy.spy(win.console, 'log').as('console.log')
},
})
});
it('loads', () => {
cy.get('@console.log').should('be.calledWith', 'Started the game')
cy.get('@console.log').should('be.calledWith', 'Preloading')
cy.get('@console.log').should('be.calledWith', 'Preloading done')
cy.get('@console.log').should('be.calledWith', 'startInit')
cy.get('@console.log').should('be.calledWith', 'startInit done')
});
});

1406
e2e/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

9
e2e/package.json Normal file
View File

@ -0,0 +1,9 @@
{
"dependencies": {
"cypress": "^3.8.3"
},
"scripts": {
"cy:run": "cypress run",
"cy:open": "cypress open"
}
}

View File

@ -0,0 +1,32 @@
declare let window:any;
//this class is used to communicate with cypress, our e2e testing client
//Since cypress cannot manipulate canvas, we notified it with console logs
class CypressAsserter {
constructor() {
window.cypressAsserter = this
}
gameStarted() {
console.log('Started the game')
}
preloadStarted() {
console.log('Preloading')
}
preloadFinished() {
console.log('Preloading done')
}
initStarted() {
console.log('startInit')
}
initFinished() {
console.log('startInit done')
}
}
export const cypressAsserter = new CypressAsserter()

View File

@ -4,6 +4,7 @@ import {CurrentGamerInterface, GamerInterface, Player} from "../Player/Player";
import {DEBUG_MODE, RESOLUTION, ZOOM_LEVEL} from "../../Enum/EnvironmentVariable"; import {DEBUG_MODE, RESOLUTION, ZOOM_LEVEL} from "../../Enum/EnvironmentVariable";
import Tile = Phaser.Tilemaps.Tile; import Tile = Phaser.Tilemaps.Tile;
import {ITiledMap, ITiledTileSet} from "../Map/ITiledMap"; import {ITiledMap, ITiledTileSet} from "../Map/ITiledMap";
import {cypressAsserter} from "../../Cypress/CypressAsserter";
export enum Textures { export enum Textures {
Rock = 'rock', Rock = 'rock',
@ -42,6 +43,7 @@ export class GameScene extends Phaser.Scene implements GameSceneInterface{
//hook preload scene //hook preload scene
preload(): void { preload(): void {
cypressAsserter.preloadStarted();
let mapUrl = 'maps/map.json'; let mapUrl = 'maps/map.json';
this.load.on('filecomplete-tilemapJSON-'+Textures.Map, (key: string, type: string, data: any) => { this.load.on('filecomplete-tilemapJSON-'+Textures.Map, (key: string, type: string, data: any) => {
// Triggered when the map is loaded // Triggered when the map is loaded
@ -62,6 +64,7 @@ export class GameScene extends Phaser.Scene implements GameSceneInterface{
'resources/characters/pipoya/Male 01-1.png', 'resources/characters/pipoya/Male 01-1.png',
{ frameWidth: 32, frameHeight: 32 } { frameWidth: 32, frameHeight: 32 }
); );
cypressAsserter.preloadFinished();
} }
//hook initialisation //hook initialisation
@ -69,6 +72,7 @@ export class GameScene extends Phaser.Scene implements GameSceneInterface{
//hook create scene //hook create scene
create(): void { create(): void {
cypressAsserter.initStarted();
//initalise map //initalise map
this.Map = this.add.tilemap("map"); this.Map = this.add.tilemap("map");
@ -110,6 +114,7 @@ export class GameScene extends Phaser.Scene implements GameSceneInterface{
//initialise camera //initialise camera
this.initCamera(); this.initCamera();
cypressAsserter.initFinished();
} }
//todo: in a dedicated class/function? //todo: in a dedicated class/function?

View File

@ -2,6 +2,7 @@ import 'phaser';
import GameConfig = Phaser.Types.Core.GameConfig; import GameConfig = Phaser.Types.Core.GameConfig;
import {GameManager} from "./Phaser/Game/GameManager"; import {GameManager} from "./Phaser/Game/GameManager";
import {DEBUG_MODE, RESOLUTION} from "./Enum/EnvironmentVariable"; import {DEBUG_MODE, RESOLUTION} from "./Enum/EnvironmentVariable";
import {cypressAsserter} from "./Cypress/CypressAsserter";
let gameManager = new GameManager(); let gameManager = new GameManager();
@ -20,6 +21,8 @@ const config: GameConfig = {
} }
}; };
cypressAsserter.gameStarted();
gameManager.createGame().then(() => { gameManager.createGame().then(() => {
let game = new Phaser.Game(config); let game = new Phaser.Game(config);