openscad-playground/tests/e2e.test.js
2025-08-16 18:21:01 +02:00

159 lines
4.8 KiB
JavaScript

const longTimeout = 60000;
const isProd = process.env.NODE_ENV === 'production';
const baseUrl = isProd ? 'http://localhost:3000/dist/' : 'http://localhost:4000/';
const messages = [];
beforeAll(async () => {
page.on('console', (msg) => messages.push({
type: msg.type(),
text: msg.text(),
stack: msg.stackTrace(),
location: msg.location(),
}));
});
beforeEach(async () => {
messages.length = 0;
await page.goto('about:blank');
});
afterEach(async () => {
// console.log('Messages:', JSON.stringify(messages, null, 2));
const testName = expect.getState().currentTestName;
console.log(`[${testName}] Messages:`, JSON.stringify(messages.map(({ text }) => text), null, 2));
const errors = messages.filter(msg =>
msg.type === 'error' &&
!(msg.text.includes('404')
&& msg.stack.some(s =>
s.url.indexOf('fonts/InterVariable.woff') >= 0)));
expect(errors).toHaveLength(0);
});
function loadSrc(src) {
return page.goto(`${baseUrl}#src=${encodeURIComponent(src)}`);
}
function loadPath(path) {
return page.goto(`${baseUrl}#path=${encodeURIComponent(path)}`);
}
function loadUrl(url) {
return page.goto(`${baseUrl}#url=${encodeURIComponent(url)}`);
}
async function waitForViewer() {
await page.waitForSelector('model-viewer');
await page.waitForFunction(() => {
const viewer = document.querySelector('model-viewer.main-viewer');
return viewer && viewer.src !== '';
});
}
function expectMessage(messages, line) {
const successMessage = messages.filter(msg => msg.type === 'debug' && msg.text === line);
expect(successMessage).toHaveLength(1);
}
function expectObjectList() {
expectMessage(messages, 'stderr: Top level object is a list of objects:');
}
function expect3DPolySet() {
expectMessage(messages, 'stderr: Top level object is a 3D object (PolySet):');
}
function expect3DManifold() {
expectMessage(messages, 'stderr: Top level object is a 3D object (manifold):');
}
function waitForCustomizeButton() {
return page.waitForFunction(() => {
// Try multiple selectors for PrimeReact components
// ToggleButton might render as button or input elements
const selectors = [
'input[role=switch]',
'button',
'[role=tab]',
'.p-togglebutton',
'.p-tabmenu-nav a'
];
for (const selector of selectors) {
const elements = document.querySelectorAll(selector);
for (const element of elements) {
const text = element.textContent || element.innerText || '';
const parentText = element.parentElement?.textContent || element.parentElement?.innerText || '';
if (text.includes('Customize') || parentText.includes('Customize')) {
return element;
}
}
}
return null;
}, { timeout: 45000 }); // Increase timeout to 45 seconds
}
function waitForLabel(text) {
return page.waitForFunction(() => {
return Array.from(document.querySelectorAll('label')).find(el => el.textContent === 'myVar');
// return Array.from(document.querySelectorAll('label')).find(el => el.textContent === text);
});
}
describe('e2e', () => {
test('load the default page', async () => {
await page.goto(baseUrl);
await waitForViewer();
expectObjectList();
}, longTimeout);
test('can render cube', async () => {
await loadSrc('cube([10, 10, 10]);');
await waitForViewer();
expect3DPolySet();
}, longTimeout);
test('use BOSL2', async () => {
await loadSrc(`
include <BOSL2/std.scad>;
prismoid([40,40], [0,0], h=20);
`);
await waitForViewer();
expect3DPolySet();
}, longTimeout);
test('use NopSCADlib', async () => {
await loadSrc(`
include <NopSCADlib/vitamins/led_meters.scad>
meter(led_meter);
`);
await waitForViewer();
expect3DManifold();
}, longTimeout);
test('load a demo by path', async () => {
await loadPath('/libraries/closepoints/demo_3D_art.scad');
await waitForViewer();
expect3DPolySet();
}, longTimeout);
test('load a demo by url', async () => {
await loadUrl('https://github.com/tenstad/keyboard/blob/main/keyboard.scad');
await waitForViewer();
expect3DManifold();
}, longTimeout);
test('customizer & windows line endings work', async () => {
await loadSrc([
'myVar = 10;',
'cube(myVar);',
].join('\r\n'));
await waitForViewer();
expect3DPolySet();
// Wait for syntax checking to complete and parameters to be detected
await page.waitForFunction(() => {
// Look for any indication that parameters have been processed
const messages = Array.from(document.querySelectorAll('*')).map(el => el.textContent || '').join(' ');
return messages.includes('myVar') || messages.includes('Customize');
}, { timeout: 30000 });
await (await waitForCustomizeButton()).click();
await page.waitForSelector('fieldset');
await waitForLabel('myVar');
}, longTimeout);
});