diff --git a/tests/stress/experiment/client/src/App.jsx b/tests/stress/experiment/client/src/App.jsx index 7a8fae4..c445cc5 100644 --- a/tests/stress/experiment/client/src/App.jsx +++ b/tests/stress/experiment/client/src/App.jsx @@ -1,5 +1,8 @@ import { EmpiricaClassic } from "@empirica/core/player/classic"; -import { EmpiricaContext } from "@empirica/core/player/classic/react"; +import { + EmpiricaContext, + usePlayer, +} from "@empirica/core/player/classic/react"; import { EmpiricaMenu, EmpiricaParticipant } from "@empirica/core/player/react"; import React from "react"; import { Game } from "./Game"; @@ -11,6 +14,9 @@ export default function App() { const { protocol, host } = window.location; const url = `${protocol}//${host}/query`; + // const introSteps = function () { + // return [DemoIntro]; + // }; // const introSteps = [DemoIntro]; const introSteps = []; @@ -35,11 +41,17 @@ export default function App() { } export function DemoIntro({ next }) { + const player = usePlayer(); + + if (player.get("treatment")) { + console.log("player treatment found"); + } + return (

Intro

-
diff --git a/tests/stress/tests/actor.js b/tests/stress/tests/actor.js index f736f7e..7705fe5 100644 --- a/tests/stress/tests/actor.js +++ b/tests/stress/tests/actor.js @@ -1,5 +1,6 @@ import chalk from "chalk"; import { error } from "./helpers"; +import { sleep } from "./utils"; export class Actor { constructor(ctx, name, url) { @@ -14,6 +15,7 @@ export class Actor { this.wsSent = []; this.wsReceived = []; this.wsClose = []; + this.matchingRegexes = []; } async start(context) { @@ -25,6 +27,13 @@ export class Actor { return; } + for (const { regex, cb } of this.matchingRegexes) { + if (regex.test(text)) { + cb(); + return; + } + } + console.info(this.msgTypeConsole(msg.type()), text); }); @@ -58,6 +67,34 @@ export class Actor { ); } + async expectLogMatching(regex, cb, options = { wait: 5000, interval: 200 }) { + const start = Date.now(); + + let matched = false; + this.matchingRegexes.push({ + regex, + cb: (text) => { + matched = true; + }, + }); + + await cb(); + + while (true) { + if (matched) { + return; + } + + if (Date.now() - start > options.wait) { + break; + } + + await sleep(options.interval); + } + + throw new Error(`log not found ${regex} within ${options.wait}ms`); + } + /** * Listen to WSs. * @param {Object} cbs - Callbacks. diff --git a/tests/stress/tests/intro.spec.js b/tests/stress/tests/intro.spec.js new file mode 100644 index 0000000..70a9b67 --- /dev/null +++ b/tests/stress/tests/intro.spec.js @@ -0,0 +1,58 @@ +// @ts-check +/// + +const { test } = require("@playwright/test"); +import { Context } from "./context"; +import { adminNewBatch, quickGame } from "./admin"; +import { + gameStart, + playerSignIn, + playerStart, + submitIntroStep, + submitStage, + waitGameFinished, +} from "./player"; +import { sleep } from "./utils"; + +// At the moment, we use the same empirica server for all tests, so we need to +// run them serially. This will change when we have a dedicated server for each +// test. +test.describe.configure({ mode: "serial" }); + +// This test is a test to see if the player.get("treatment") is working +// correctly in the intro step. +// WARNING: this must be run with: +// const introSteps = [DemoIntro]; +// in the App.jsx file. This cannot be run with other tests and is normally +// disabled. When you need to run it, mark this test with .only and run it +// separately. +test.skip("intro player treament", async ({ browser }) => { + const ctx = new Context(browser); + + const playerCount = 1; + const roundCount = 1; + const stageCount = 1; + + ctx.logMatching(/player treatment found/); + + await ctx.start(); + await ctx.addPlayers(playerCount); + ctx.players[0].logWS(); + ctx.players[0].listenScope("game"); + + await ctx.applyAdmin( + adminNewBatch({ + treatmentConfig: quickGame(playerCount, roundCount, stageCount), + }) + ); + + await ctx.players[0].expectLogMatching(/player treatment found/, async () => { + await ctx.applyPlayers(playerSignIn); + await ctx.applyPlayers(submitIntroStep); + }); + await ctx.applyPlayers(gameStart); + await ctx.applyPlayers(submitStage); + await ctx.applyPlayers(waitGameFinished); + + await ctx.close(); +}); diff --git a/tests/stress/tests/player.js b/tests/stress/tests/player.js index c127985..16fd2e0 100644 --- a/tests/stress/tests/player.js +++ b/tests/stress/tests/player.js @@ -338,6 +338,22 @@ export class Player extends Actor { } } +export const playerSignIn = new Step("start game", async (actor) => { + // Fill the form + actor.info("fill form"); + await actor.page.locator("input#playerID").fill(actor.uniqueID); + await actor.page.locator(`button[type="submit"]`).click(); +}); + +export const gameStart = new Step("start game", async (actor) => { + // Wait for first stage to be visible + actor.info("signed in"); + await actor.page.getByTestId("stage-ongoing").waitFor({ timeout: 3000000 }); + + actor.info("game started"); + await actor.screenshot("game started"); +}); + export const playerStart = new Step("start game", async (actor) => { // Fill the form actor.info("fill form"); @@ -364,6 +380,11 @@ export const submitStage = new Step("submit stage", async (actor) => { // await actor.page.getByTestId("submitted").waitFor({ timeout: 5000 }); }); +export const submitIntroStep = new Step("submit intro step", async (actor) => { + await actor.page.getByTestId("intro-step").waitFor({ timeout: 5000 }); + await actor.page.getByTestId("submit-intro-step").click({ timeout: 5000 }); +}); + export const waitNextStage = new Step("wait next stage", async (actor) => { // Make sure the previous stage is finished await actor.page