Improving tests, WIP
This commit is contained in:
parent
9bba6069b4
commit
78ee4009c8
@ -59,9 +59,43 @@ $ docker-compose exec back yarn run pretty
|
||||
|
||||
WorkAdventure is based on a video game engine (Phaser), and video games are not the easiest programs to unit test.
|
||||
|
||||
Nevertheless, if your code can be unit tested, please provide a unit test (we use Jasmine).
|
||||
Nevertheless, if your code can be unit tested, please provide a unit test (we use Jasmine), or an end-to-end test (we use Testcafe).
|
||||
|
||||
If you are providing a new feature, you should setup a test map in the `maps/tests` directory. The test map should contain
|
||||
some description text describing how to test the feature. Finally, you should modify the `maps/tests/index.html` file
|
||||
to add a reference to your newly created test map.
|
||||
some description text describing how to test the feature.
|
||||
|
||||
* if the features is meant to be manually tested, you should modify the `maps/tests/index.html` file to add a reference
|
||||
to your newly created test map
|
||||
* if the features can be automatically tested, please provide a testcafe test
|
||||
|
||||
#### Running testcafe tests
|
||||
|
||||
End-to-end tests are available in the "/tests" directory.
|
||||
|
||||
To run these tests locally:
|
||||
|
||||
```console
|
||||
$ LIVE_RELOAD=0 docker-compose up -d
|
||||
$ cd tests
|
||||
$ npm install
|
||||
$ npm run test
|
||||
```
|
||||
|
||||
Note: If your tests fail on a Javascript error in "sockjs", this is due to the
|
||||
Webpack live reload. The Webpack live reload feature is conflicting with testcafe. This is why we recommend starting
|
||||
WorkAdventure with the `LIVE_RELOAD=0` environment variable.
|
||||
|
||||
End-to-end tests can take a while to run. To run only one test, use:
|
||||
|
||||
```console
|
||||
$ npm run test -- tests/[name of the test file].ts
|
||||
```
|
||||
|
||||
You can also run the tests inside a container (but you will not have visual feedbacks on your test, so we recommend using
|
||||
the local tests).
|
||||
|
||||
```console
|
||||
$ LIVE_RELOAD=0 docker-compose up -d
|
||||
# Wait 2-3 minutes for the environment to start, then:
|
||||
$ docker-compose -f docker-compose.testcafe.yaml up
|
||||
```
|
||||
|
@ -3,6 +3,7 @@ import { Scene } from "phaser";
|
||||
import { ErrorScene, ErrorSceneName } from "../Reconnecting/ErrorScene";
|
||||
import { WAError } from "../Reconnecting/WAError";
|
||||
import { waScaleManager } from "../Services/WaScaleManager";
|
||||
import { ReconnectingTextures } from "../Reconnecting/ReconnectingScene";
|
||||
|
||||
export const EntrySceneName = "EntryScene";
|
||||
|
||||
@ -17,6 +18,14 @@ export class EntryScene extends Scene {
|
||||
});
|
||||
}
|
||||
|
||||
// From the very start, let's preload images used in the ReconnectingScene.
|
||||
preload() {
|
||||
this.load.image(ReconnectingTextures.icon, "static/images/favicons/favicon-32x32.png");
|
||||
// Note: arcade.png from the Phaser 3 examples at: https://github.com/photonstorm/phaser3-examples/tree/master/public/assets/fonts/bitmap
|
||||
this.load.bitmapFont(ReconnectingTextures.mainFont, "resources/fonts/arcade.png", "resources/fonts/arcade.xml");
|
||||
this.load.spritesheet("cat", "resources/characters/pipoya/Cat 01-1.png", { frameWidth: 32, frameHeight: 32 });
|
||||
}
|
||||
|
||||
create() {
|
||||
gameManager
|
||||
.init(this.scene)
|
||||
|
@ -3,7 +3,7 @@ import Image = Phaser.GameObjects.Image;
|
||||
import Sprite = Phaser.GameObjects.Sprite;
|
||||
|
||||
export const ReconnectingSceneName = "ReconnectingScene";
|
||||
enum ReconnectingTextures {
|
||||
export enum ReconnectingTextures {
|
||||
icon = "icon",
|
||||
mainFont = "main_font",
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ const BROWSER = process.env.BROWSER || "chrome --use-fake-ui-for-media-stream --
|
||||
module.exports = {
|
||||
"browsers": BROWSER,
|
||||
"hostname": "localhost",
|
||||
//"skipJsErrors": true,
|
||||
"src": "tests/",
|
||||
"screenshots": {
|
||||
"path": "screenshots/",
|
||||
@ -12,4 +11,15 @@ module.exports = {
|
||||
},
|
||||
"assertionTimeout": 10000,
|
||||
"selectorTimeout": 40000,
|
||||
|
||||
/*"skipJsErrors": true,
|
||||
"clientScripts": [ { "content": `
|
||||
window.addEventListener('error', function (e) {
|
||||
if (e instanceof Error && e.message.includes('_jp')) {
|
||||
console.log('Ignoring sockjs related error');
|
||||
return;
|
||||
}
|
||||
throw e;
|
||||
});
|
||||
` } ]*/
|
||||
}
|
||||
|
43
tests/package-lock.json
generated
43
tests/package-lock.json
generated
@ -5,7 +5,8 @@
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"@types/dockerode": "^3.3.0"
|
||||
"@types/dockerode": "^3.3.0",
|
||||
"axios": "^0.24.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"dockerode": "^3.3.1",
|
||||
@ -2095,6 +2096,14 @@
|
||||
"node": ">= 4.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "0.24.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
|
||||
"integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.4"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-dynamic-import-node": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz",
|
||||
@ -3031,6 +3040,25 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.14.5",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz",
|
||||
"integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
@ -6843,6 +6871,14 @@
|
||||
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
|
||||
"dev": true
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.24.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
|
||||
"integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.14.4"
|
||||
}
|
||||
},
|
||||
"babel-plugin-dynamic-import-node": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz",
|
||||
@ -7594,6 +7630,11 @@
|
||||
"locate-path": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.14.5",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz",
|
||||
"integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA=="
|
||||
},
|
||||
"fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
|
@ -7,6 +7,7 @@
|
||||
"test": "testcafe"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/dockerode": "^3.3.0"
|
||||
"@types/dockerode": "^3.3.0",
|
||||
"axios": "^0.24.0"
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ const fs = require('fs');
|
||||
const Docker = require('dockerode');
|
||||
import { Selector } from 'testcafe';
|
||||
import {userAlice} from "./utils/roles";
|
||||
import {findContainer, rebootBack, rebootPusher, rebootRedis, startContainer, stopContainer} from "./utils/containers";
|
||||
import {findContainer, rebootBack, rebootPusher, resetRedis, startContainer, stopContainer} from "./utils/containers";
|
||||
|
||||
fixture `Reconnection`
|
||||
.page `http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/mousewheel.json`;
|
||||
|
@ -1,7 +1,9 @@
|
||||
//import Docker from "dockerode";
|
||||
//import * as Dockerode from "dockerode";
|
||||
import Dockerode = require( 'dockerode')
|
||||
|
||||
const util = require('util');
|
||||
const exec = util.promisify(require('child_process').exec);
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
/**
|
||||
* Returns a container ID based on the container name.
|
||||
@ -33,19 +35,81 @@ export async function startContainer(container: Dockerode.ContainerInfo): Promis
|
||||
}
|
||||
|
||||
export async function rebootBack(): Promise<void> {
|
||||
const container = await findContainer('back');
|
||||
let stdout = execSync('docker-compose up --force-recreate -d back', {
|
||||
cwd: __dirname + '/../../../'
|
||||
});
|
||||
/*const container = await findContainer('back');
|
||||
await stopContainer(container);
|
||||
await startContainer(container);
|
||||
await startContainer(container);*/
|
||||
}
|
||||
|
||||
export function rebootTraefik(): void {
|
||||
let stdout = execSync('docker-compose up --force-recreate -d reverse-proxy', {
|
||||
cwd: __dirname + '/../../../'
|
||||
});
|
||||
|
||||
//console.log('rebootTraefik', stdout);
|
||||
}
|
||||
|
||||
export async function rebootPusher(): Promise<void> {
|
||||
const container = await findContainer('pusher');
|
||||
let stdout = execSync('docker-compose up --force-recreate -d pusher', {
|
||||
cwd: __dirname + '/../../../'
|
||||
});
|
||||
/*const container = await findContainer('pusher');
|
||||
await stopContainer(container);
|
||||
await startContainer(container);
|
||||
await startContainer(container);*/
|
||||
}
|
||||
|
||||
export async function rebootRedis(): Promise<void> {
|
||||
const container = await findContainer('redis');
|
||||
await stopContainer(container);
|
||||
await startContainer(container);
|
||||
export async function resetRedis(): Promise<void> {
|
||||
let stdout = execSync('docker-compose stop redis', {
|
||||
cwd: __dirname + '/../../../'
|
||||
});
|
||||
//console.log('rebootRedis', stdout);
|
||||
|
||||
stdout = execSync('docker-compose rm -f redis', {
|
||||
cwd: __dirname + '/../../../'
|
||||
});
|
||||
//console.log('rebootRedis', stdout);
|
||||
|
||||
stdout = execSync('docker-compose up --force-recreate -d redis', {
|
||||
cwd: __dirname + '/../../../'
|
||||
});
|
||||
|
||||
//console.log('rebootRedis', stdout);
|
||||
/*
|
||||
let stdout = execSync('docker-compose stop redis', {
|
||||
cwd: __dirname + '/../../../'
|
||||
});
|
||||
console.log('stdout:', stdout);
|
||||
stdout = execSync('docker-compose rm redis', {
|
||||
cwd: __dirname + '/../../../'
|
||||
});
|
||||
//const { stdout, stderr } = await exec('docker-compose down redis');
|
||||
console.log('stdout:', stdout);
|
||||
//console.log('stderr:', stderr);
|
||||
const { stdout2, stderr2 } = await exec('docker-compose up -d redis');
|
||||
console.log('stdout:', stdout2);
|
||||
console.log('stderr:', stderr2);
|
||||
*/
|
||||
/*const container = await findContainer('redis');
|
||||
//await stopContainer(container);
|
||||
//await startContainer(container);
|
||||
|
||||
const docker = new Dockerode();
|
||||
await docker.getContainer(container.Id).stop();
|
||||
await docker.getContainer(container.Id).remove();
|
||||
const newContainer = await docker.createContainer(container);
|
||||
await newContainer.start();*/
|
||||
}
|
||||
|
||||
export function stopRedis(): void {
|
||||
let stdout = execSync('docker-compose stop redis', {
|
||||
cwd: __dirname + '/../../../'
|
||||
});
|
||||
}
|
||||
|
||||
export function startRedis(): void {
|
||||
let stdout = execSync('docker-compose start redis', {
|
||||
cwd: __dirname + '/../../../'
|
||||
});
|
||||
}
|
||||
|
17
tests/tests/utils/debug.ts
Normal file
17
tests/tests/utils/debug.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import axios from "axios";
|
||||
|
||||
export async function getPusherDump(): Promise<any> {
|
||||
return (await axios({
|
||||
url: 'http://pusher.workadventure.localhost/dump?token=123',
|
||||
method: 'get',
|
||||
})).data;
|
||||
}
|
||||
|
||||
|
||||
export async function getBackDump(): Promise<any> {
|
||||
return (await axios({
|
||||
url: 'http://api.workadventure.localhost/dump?token=123',
|
||||
method: 'get',
|
||||
})).data;
|
||||
}
|
||||
|
@ -1,5 +1,16 @@
|
||||
import { Role } from 'testcafe';
|
||||
|
||||
export const userAliceOnPage = (url: string) => Role(url, async t => {
|
||||
await t
|
||||
.typeText('input[name="loginSceneName"]', 'Alice')
|
||||
.click('button.loginSceneFormSubmit')
|
||||
.click('button.selectCharacterButtonRight')
|
||||
.click('button.selectCharacterButtonRight')
|
||||
.click('button.selectCharacterSceneFormSubmit')
|
||||
.click('button.letsgo');
|
||||
});
|
||||
|
||||
|
||||
export const userAlice = Role('http://play.workadventure.localhost/', async t => {
|
||||
await t
|
||||
.typeText('input[name="loginSceneName"]', 'Alice')
|
||||
|
@ -3,8 +3,17 @@ import {assertLogMessage} from "./utils/log";
|
||||
const fs = require('fs');
|
||||
const Docker = require('dockerode');
|
||||
import { Selector } from 'testcafe';
|
||||
import {userAlice} from "./utils/roles";
|
||||
import {findContainer, rebootBack, rebootPusher, rebootRedis, startContainer, stopContainer} from "./utils/containers";
|
||||
import {userAlice, userAliceOnPage} from "./utils/roles";
|
||||
import {
|
||||
findContainer,
|
||||
rebootBack,
|
||||
rebootPusher,
|
||||
resetRedis,
|
||||
rebootTraefik,
|
||||
startContainer,
|
||||
stopContainer, stopRedis, startRedis
|
||||
} from "./utils/containers";
|
||||
import {getPusherDump} from "./utils/debug";
|
||||
|
||||
// Note: we are also testing that passing a random query parameter does not cause any issue.
|
||||
fixture `Variables`
|
||||
@ -14,21 +23,75 @@ test("Test that variables storage works", async (t: TestController) => {
|
||||
|
||||
const variableInput = Selector('#textField');
|
||||
|
||||
await resetRedis();
|
||||
|
||||
await Promise.all([
|
||||
rebootBack(),
|
||||
rebootRedis(),
|
||||
rebootPusher(),
|
||||
]);
|
||||
|
||||
await t.useRole(userAlice)
|
||||
//const mainWindow = await t.getCurrentWindow();
|
||||
|
||||
await t.useRole(userAliceOnPage('http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/shared_variables.json?somerandomparam=1'))
|
||||
.switchToIframe("#cowebsite-buffer iframe")
|
||||
.expect(variableInput.value).eql('default value')
|
||||
.selectText(variableInput)
|
||||
.pressKey('delete')
|
||||
.typeText(variableInput, 'new value')
|
||||
.switchToPreviousWindow()
|
||||
.pressKey('tab')
|
||||
.switchToMainWindow()
|
||||
//.switchToWindow(mainWindow)
|
||||
.wait(500)
|
||||
// reload
|
||||
/*.navigateTo('http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/shared_variables.json')
|
||||
.navigateTo('http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/shared_variables.json')
|
||||
.switchToIframe("#cowebsite-buffer iframe")
|
||||
.expect(variableInput.value).eql('new value')*/
|
||||
.expect(variableInput.value).eql('new value')
|
||||
//.debug()
|
||||
.switchToMainWindow()
|
||||
//.switchToWindow(mainWindow)
|
||||
/*
|
||||
.wait(5000)
|
||||
//.debug()
|
||||
.switchToIframe("#cowebsite-buffer iframe")
|
||||
.expect(variableInput.value).eql('new value')
|
||||
.switchToMainWindow();*/
|
||||
|
||||
// Now, let's kill the reverse proxy to cut the connexion
|
||||
//console.log('Rebooting traefik');
|
||||
await rebootTraefik();
|
||||
//console.log('Rebooting done');
|
||||
|
||||
|
||||
await t
|
||||
.switchToIframe("#cowebsite-buffer iframe")
|
||||
.expect(variableInput.value).eql('new value')
|
||||
|
||||
stopRedis();
|
||||
|
||||
// Redis is stopped, let's try to modify a variable.
|
||||
await t.selectText(variableInput)
|
||||
.pressKey('delete')
|
||||
.typeText(variableInput, 'value set while Redis stopped')
|
||||
.pressKey('tab')
|
||||
.switchToMainWindow()
|
||||
|
||||
startRedis();
|
||||
|
||||
// Navigate to some other map so that the pusher connection is freed.
|
||||
await t.navigateTo('http://maps.workadventure.localhost/tests/');
|
||||
|
||||
// TODO: check that Back and Pusher rooms are unloaded
|
||||
// TODO: check that Back and Pusher rooms are unloaded
|
||||
// TODO: check that Back and Pusher rooms are unloaded
|
||||
// TODO: check that Back and Pusher rooms are unloaded
|
||||
console.log(await getPusherDump());
|
||||
|
||||
await t.navigateTo('http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/shared_variables.json')
|
||||
.switchToIframe("#cowebsite-buffer iframe")
|
||||
// Redis will reconnect automatically and will store the variable on reconnect!
|
||||
// So we should see the new value.
|
||||
.expect(variableInput.value).eql('value set while Redis stopped')
|
||||
.switchToMainWindow()
|
||||
|
||||
|
||||
|
||||
@ -50,7 +113,7 @@ test("Test that variables storage works", async (t: TestController) => {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
test("Test that variables cache in the back don't prevent setting a variable in case the map changes", async (t: TestController) => {
|
||||
// Let's start by visiting a map that DOES not have the variable.
|
||||
fs.copyFileSync('../maps/tests/Variables/Cache/variables_cache_1.json', '../maps/tests/Variables/Cache/variables_tmp.json');
|
||||
@ -77,3 +140,4 @@ test("Test that variables cache in the back don't prevent setting a variable in
|
||||
}
|
||||
});
|
||||
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user