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 (
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