195 lines
8.4 KiB
JavaScript
195 lines
8.4 KiB
JavaScript
#!/usr/bin/env node
|
|||
|
|
"use strict";
|
||
|
|
|
||
|
|
const assert = require("node:assert");
|
||
|
|
const { chromium } = require("playwright");
|
||
|
|
|
||
|
|
const BASE_URL = (process.env.MNOTE_UI_BASE_URL || "http://127.0.0.1:3000").replace(/\/+$/, "");
|
||
|
|
const UI_TIMEOUT_MS = Number(process.env.MNOTE_UI_TIMEOUT_MS || 45000);
|
||
|
|
|
||
|
|
async function main() {
|
||
|
|
const browser = await chromium.launch({ headless: true });
|
||
|
|
const context = await browser.newContext();
|
||
|
|
const page = await context.newPage();
|
||
|
|
const consoleErrors = [];
|
||
|
|
const networkFailures = [];
|
||
|
|
page.on("console", (message) => {
|
||
|
|
if (message.type() === "error") consoleErrors.push(message.text());
|
||
|
|
});
|
||
|
|
page.on("requestfailed", (request) => {
|
||
|
|
networkFailures.push({ url: request.url(), failure: request.failure()?.errorText || "" });
|
||
|
|
});
|
||
|
|
|
||
|
|
await page.goto(`${BASE_URL}/auth`, { waitUntil: "domcontentloaded", timeout: UI_TIMEOUT_MS });
|
||
|
|
const result = await page.evaluate(async () => {
|
||
|
|
const suffix = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
||
|
|
const sessionA = `mnote-oo-browser-a-${suffix}`;
|
||
|
|
const sessionB = `mnote-oo-browser-b-${suffix}`;
|
||
|
|
const tokenA = `token-a-${suffix}`;
|
||
|
|
const tokenB = `token-b-${suffix}`;
|
||
|
|
|
||
|
|
async function postJson(path, payload) {
|
||
|
|
const response = await fetch(path, {
|
||
|
|
method: "POST",
|
||
|
|
headers: { "content-type": "application/json" },
|
||
|
|
body: JSON.stringify(payload),
|
||
|
|
});
|
||
|
|
const body = await response.json().catch(() => null);
|
||
|
|
return { status: response.status, body };
|
||
|
|
}
|
||
|
|
|
||
|
|
async function getJson(path) {
|
||
|
|
const response = await fetch(path);
|
||
|
|
const body = response.status === 204 ? null : await response.json().catch(() => null);
|
||
|
|
return { status: response.status, body };
|
||
|
|
}
|
||
|
|
|
||
|
|
const registeredA = await postJson("/api/onlyoffice/bridge/session", {
|
||
|
|
sessionId: sessionA,
|
||
|
|
token: tokenA,
|
||
|
|
editorType: "word",
|
||
|
|
documentId: "doc_a",
|
||
|
|
assetId: "asset_a",
|
||
|
|
fileType: "docx",
|
||
|
|
docKey: "doc_key_a",
|
||
|
|
pageOrigin: location.origin,
|
||
|
|
});
|
||
|
|
const registeredB = await postJson("/api/onlyoffice/bridge/session", {
|
||
|
|
sessionId: sessionB,
|
||
|
|
token: tokenB,
|
||
|
|
editorType: "word",
|
||
|
|
documentId: "doc_b",
|
||
|
|
assetId: "asset_b",
|
||
|
|
fileType: "docx",
|
||
|
|
docKey: "doc_key_b",
|
||
|
|
pageOrigin: location.origin,
|
||
|
|
});
|
||
|
|
const wrongToken = await getJson(`/api/onlyoffice/bridge/commands/next?sessionId=${encodeURIComponent(sessionA)}&token=${encodeURIComponent(tokenB)}&timeoutMs=1`);
|
||
|
|
|
||
|
|
const commandA = await postJson("/api/onlyoffice/bridge/commands", {
|
||
|
|
sessionId: sessionA,
|
||
|
|
token: tokenA,
|
||
|
|
action: "document.insert_text",
|
||
|
|
payload: { text: "A" },
|
||
|
|
});
|
||
|
|
const commandB = await postJson("/api/onlyoffice/bridge/commands", {
|
||
|
|
sessionId: sessionB,
|
||
|
|
token: tokenB,
|
||
|
|
action: "document.insert_text",
|
||
|
|
payload: { text: "B" },
|
||
|
|
});
|
||
|
|
|
||
|
|
const nextA = await getJson(`/api/onlyoffice/bridge/commands/next?sessionId=${encodeURIComponent(sessionA)}&token=${encodeURIComponent(tokenA)}&timeoutMs=1000`);
|
||
|
|
const nextB = await getJson(`/api/onlyoffice/bridge/commands/next?sessionId=${encodeURIComponent(sessionB)}&token=${encodeURIComponent(tokenB)}&timeoutMs=1000`);
|
||
|
|
|
||
|
|
const postedA = await postJson("/api/onlyoffice/bridge/results", {
|
||
|
|
sessionId: sessionA,
|
||
|
|
token: tokenA,
|
||
|
|
id: nextA.body && nextA.body.id,
|
||
|
|
ok: true,
|
||
|
|
result: { text: "result-a" },
|
||
|
|
});
|
||
|
|
const postedB = await postJson("/api/onlyoffice/bridge/results", {
|
||
|
|
sessionId: sessionB,
|
||
|
|
token: tokenB,
|
||
|
|
id: nextB.body && nextB.body.id,
|
||
|
|
ok: true,
|
||
|
|
result: { text: "result-b" },
|
||
|
|
});
|
||
|
|
|
||
|
|
const resultA = await getJson(`/api/onlyoffice/bridge/results?sessionId=${encodeURIComponent(sessionA)}&token=${encodeURIComponent(tokenA)}&commandId=${encodeURIComponent(nextA.body && nextA.body.id)}&timeoutMs=1000`);
|
||
|
|
const resultB = await getJson(`/api/onlyoffice/bridge/results?sessionId=${encodeURIComponent(sessionB)}&token=${encodeURIComponent(tokenB)}&commandId=${encodeURIComponent(nextB.body && nextB.body.id)}&timeoutMs=1000`);
|
||
|
|
const sessions = await getJson("/api/onlyoffice/bridge/sessions");
|
||
|
|
const currentBeforeClose = await getJson("/api/onlyoffice/bridge/session/current");
|
||
|
|
const closeA = await postJson("/api/onlyoffice/bridge/session/close", {
|
||
|
|
sessionId: sessionA,
|
||
|
|
token: tokenA,
|
||
|
|
});
|
||
|
|
const nextAAfterClose = await getJson(`/api/onlyoffice/bridge/commands/next?sessionId=${encodeURIComponent(sessionA)}&token=${encodeURIComponent(tokenA)}&timeoutMs=1`);
|
||
|
|
const sessionsAfterClose = await getJson("/api/onlyoffice/bridge/sessions");
|
||
|
|
|
||
|
|
return {
|
||
|
|
sessionA,
|
||
|
|
sessionB,
|
||
|
|
registeredA,
|
||
|
|
registeredB,
|
||
|
|
wrongToken,
|
||
|
|
commandA,
|
||
|
|
commandB,
|
||
|
|
nextA,
|
||
|
|
nextB,
|
||
|
|
postedA,
|
||
|
|
postedB,
|
||
|
|
resultA,
|
||
|
|
resultB,
|
||
|
|
sessions,
|
||
|
|
currentBeforeClose,
|
||
|
|
closeA,
|
||
|
|
nextAAfterClose,
|
||
|
|
sessionsAfterClose,
|
||
|
|
};
|
||
|
|
});
|
||
|
|
|
||
|
|
assert.equal(result.registeredA.status, 200, JSON.stringify(result.registeredA));
|
||
|
|
assert.equal(result.registeredB.status, 200, JSON.stringify(result.registeredB));
|
||
|
|
assert.equal(result.registeredA.body.docKey, "doc_key_a");
|
||
|
|
assert.equal(result.registeredB.body.docKey, "doc_key_b");
|
||
|
|
assert.equal(result.registeredA.body.pageOrigin, BASE_URL);
|
||
|
|
assert.equal(result.registeredB.body.pageOrigin, BASE_URL);
|
||
|
|
assert.equal(result.wrongToken.status, 401, JSON.stringify(result.wrongToken));
|
||
|
|
assert.equal(result.commandA.status, 200, JSON.stringify(result.commandA));
|
||
|
|
assert.equal(result.commandB.status, 200, JSON.stringify(result.commandB));
|
||
|
|
assert.equal(result.nextA.status, 200, JSON.stringify(result.nextA));
|
||
|
|
assert.equal(result.nextB.status, 200, JSON.stringify(result.nextB));
|
||
|
|
assert.equal(result.nextA.body.action, "document.insert_text");
|
||
|
|
assert.equal(result.nextB.body.action, "document.insert_text");
|
||
|
|
assert.equal(result.nextA.body.payload.text, "A");
|
||
|
|
assert.equal(result.nextB.body.payload.text, "B");
|
||
|
|
assert.notEqual(result.nextA.body.id, result.nextB.body.id);
|
||
|
|
assert.equal(result.postedA.status, 200, JSON.stringify(result.postedA));
|
||
|
|
assert.equal(result.postedB.status, 200, JSON.stringify(result.postedB));
|
||
|
|
assert.equal(result.resultA.status, 200, JSON.stringify(result.resultA));
|
||
|
|
assert.equal(result.resultB.status, 200, JSON.stringify(result.resultB));
|
||
|
|
assert.equal(result.resultA.body.result.text, "result-a");
|
||
|
|
assert.equal(result.resultB.body.result.text, "result-b");
|
||
|
|
const sessionARecord = result.sessions.body.sessions.find((session) => session.sessionId === result.sessionA);
|
||
|
|
const sessionBRecord = result.sessions.body.sessions.find((session) => session.sessionId === result.sessionB);
|
||
|
|
assert(sessionARecord, JSON.stringify(result.sessions));
|
||
|
|
assert(sessionBRecord, JSON.stringify(result.sessions));
|
||
|
|
assert.equal(sessionARecord.docKey, "doc_key_a");
|
||
|
|
assert.equal(sessionBRecord.pageOrigin, BASE_URL);
|
||
|
|
assert.equal(result.currentBeforeClose.status, 200, JSON.stringify(result.currentBeforeClose));
|
||
|
|
assert(result.currentBeforeClose.body.session, JSON.stringify(result.currentBeforeClose));
|
||
|
|
assert.equal(result.closeA.status, 200, JSON.stringify(result.closeA));
|
||
|
|
assert.equal(result.closeA.body.closed, true, JSON.stringify(result.closeA));
|
||
|
|
assert.equal(result.nextAAfterClose.status, 401, JSON.stringify(result.nextAAfterClose));
|
||
|
|
assert(!result.sessionsAfterClose.body.sessions.some((session) => session.sessionId === result.sessionA));
|
||
|
|
assert(result.sessionsAfterClose.body.sessions.some((session) => session.sessionId === result.sessionB));
|
||
|
|
|
||
|
|
await browser.close();
|
||
|
|
console.log(JSON.stringify({
|
||
|
|
ok: true,
|
||
|
|
task: "task516-onlyoffice-bridge-multisession-browser-smoke",
|
||
|
|
baseUrl: BASE_URL,
|
||
|
|
sessionA: result.sessionA,
|
||
|
|
sessionB: result.sessionB,
|
||
|
|
wrongToken: { status: result.wrongToken.status, code: result.wrongToken.body && result.wrongToken.body.code },
|
||
|
|
nextA: { id: result.nextA.body.id, text: result.nextA.body.payload.text },
|
||
|
|
nextB: { id: result.nextB.body.id, text: result.nextB.body.payload.text },
|
||
|
|
resultA: result.resultA.body.result,
|
||
|
|
resultB: result.resultB.body.result,
|
||
|
|
currentBeforeClose: {
|
||
|
|
status: result.currentBeforeClose.status,
|
||
|
|
sessionId: result.currentBeforeClose.body.session && result.currentBeforeClose.body.session.sessionId,
|
||
|
|
},
|
||
|
|
closeA: result.closeA.body,
|
||
|
|
consoleErrors,
|
||
|
|
networkFailures,
|
||
|
|
}, null, 2));
|
||
|
|
}
|
||
|
|
|
||
|
|
main().catch((error) => {
|
||
|
|
console.error(error && error.stack ? error.stack : error);
|
||
|
|
process.exit(1);
|
||
|
|
});
|