249 lines
7.8 KiB
JavaScript
249 lines
7.8 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import process from 'node:process';
|
|
import { fileURLToPath } from 'node:url';
|
|
import tailwind from '@tailwindcss/vite';
|
|
import vue from '@vitejs/plugin-vue';
|
|
import { createInertiaApp } from '@inertiajs/vue3';
|
|
import { createServer } from 'vite';
|
|
import { createSSRApp, h } from 'vue';
|
|
import { renderToString } from 'vue/server-renderer';
|
|
|
|
const serve = process.argv.includes('--serve');
|
|
const server = await createServer({
|
|
configFile: false,
|
|
cacheDir: 'node_modules/.vite/dashboard-fixture',
|
|
plugins: [vue(), ...(serve ? [tailwind()] : [])],
|
|
resolve: {
|
|
alias: {
|
|
'@': fileURLToPath(new URL('../../resources/js', import.meta.url)),
|
|
},
|
|
},
|
|
server: serve
|
|
? { host: '127.0.0.1', port: 4180, strictPort: true, hmr: false }
|
|
: { middlewareMode: true, hmr: false, watch: null },
|
|
appType: 'custom',
|
|
});
|
|
|
|
const user = {
|
|
id: 8,
|
|
name: 'Alex Morgan',
|
|
email: 'alex@example.test',
|
|
avatar: null,
|
|
avatar_color: '#22c55e',
|
|
avatar_is_generated: true,
|
|
email_verified_at: '2026-09-11T00:00:00Z',
|
|
must_change_password_on_next_login: false,
|
|
created_at: '2026-09-11T00:00:00Z',
|
|
updated_at: '2026-09-11T00:00:00Z',
|
|
};
|
|
const project = {
|
|
id: 7,
|
|
key: 'ENG',
|
|
name: 'Engineering · Platform and developer experience',
|
|
show_author: true,
|
|
show_story_points: true,
|
|
created_at: '2026-09-11T00:00:00Z',
|
|
updated_at: '2026-09-11T00:00:00Z',
|
|
};
|
|
const secondProject = {
|
|
...project,
|
|
id: 9,
|
|
key: 'OPS',
|
|
name: 'Operations',
|
|
};
|
|
const ticketDefaults = {
|
|
acceptance_criteria: [],
|
|
assignee: user,
|
|
assignee_user_id: user.id,
|
|
author: null,
|
|
author_user_id: null,
|
|
blocked_comment: null,
|
|
description: 'Real work loaded from the server.',
|
|
is_blocked: false,
|
|
parent_ticket_id: null,
|
|
story_points: 3,
|
|
ticket_priority: {
|
|
id: 1,
|
|
name: 'Medium',
|
|
position: 3,
|
|
project_id: 7,
|
|
created_at: '2026-09-11T00:00:00Z',
|
|
updated_at: '2026-09-11T00:00:00Z',
|
|
},
|
|
ticket_priority_id: 1,
|
|
ticket_status: {
|
|
id: 3,
|
|
board_column_id: 2,
|
|
name: 'In Progress',
|
|
position: 1,
|
|
project_id: 7,
|
|
slug: 'in-progress',
|
|
created_at: '2026-09-11T00:00:00Z',
|
|
updated_at: '2026-09-11T00:00:00Z',
|
|
board_column: {
|
|
id: 2,
|
|
name: 'In Progress',
|
|
position: 2,
|
|
project_id: 7,
|
|
created_at: '2026-09-11T00:00:00Z',
|
|
updated_at: '2026-09-11T00:00:00Z',
|
|
},
|
|
},
|
|
ticket_status_id: 3,
|
|
ticket_type: {
|
|
id: 1,
|
|
is_parent: false,
|
|
name: 'Dev task',
|
|
position: 1,
|
|
project_id: 7,
|
|
created_at: '2026-09-11T00:00:00Z',
|
|
updated_at: '2026-09-11T00:00:00Z',
|
|
},
|
|
ticket_type_id: 1,
|
|
created_at: '2026-09-11T00:00:00Z',
|
|
updated_at: '2026-09-11T00:00:00Z',
|
|
};
|
|
const tickets = [
|
|
{
|
|
...ticketDefaults,
|
|
id: 42,
|
|
project_id: project.id,
|
|
sequence_number: 42,
|
|
ticket_key: 'ENG-42',
|
|
title: 'Ship the dashboard with real assigned work',
|
|
},
|
|
{
|
|
...ticketDefaults,
|
|
id: 41,
|
|
project_id: project.id,
|
|
sequence_number: 41,
|
|
ticket_key: 'ENG-41',
|
|
title: 'Verify keyboard navigation',
|
|
},
|
|
];
|
|
const blockedTicket = {
|
|
...ticketDefaults,
|
|
id: 12,
|
|
blocked_comment: 'Waiting for review.',
|
|
is_blocked: true,
|
|
project_id: secondProject.id,
|
|
sequence_number: 12,
|
|
ticket_key: 'OPS-12',
|
|
title: 'Resolve the deployment blocker',
|
|
};
|
|
const assignedTicketsByProject = [
|
|
{ project: secondProject, tickets: [blockedTicket] },
|
|
{ project, tickets },
|
|
];
|
|
|
|
function makePage(url) {
|
|
const parsedUrl = new URL(url, 'http://localhost');
|
|
const isDashboard = parsedUrl.pathname === '/dashboard';
|
|
return {
|
|
component: isDashboard ? 'Dashboard' : 'Destination',
|
|
url,
|
|
version: null,
|
|
clearHistory: false,
|
|
encryptHistory: false,
|
|
props: {
|
|
name: 'KanbanGit',
|
|
errors: {},
|
|
sidebarOpen: true,
|
|
auth: {
|
|
user,
|
|
permissions: {
|
|
globalAdmin: false,
|
|
projectCreate: false,
|
|
canManageTeams: false,
|
|
},
|
|
},
|
|
navigation: { project: null },
|
|
...(isDashboard
|
|
? {
|
|
assignedTicketsByProject: parsedUrl.searchParams.has(
|
|
'empty',
|
|
)
|
|
? []
|
|
: assignedTicketsByProject,
|
|
}
|
|
: {}),
|
|
},
|
|
};
|
|
}
|
|
|
|
if (serve) {
|
|
server.middlewares.use(async (request, response) => {
|
|
const page = makePage(request.url);
|
|
response.setHeader('Vary', 'X-Inertia');
|
|
if (request.headers['x-inertia']) {
|
|
response.setHeader('X-Inertia', 'true');
|
|
response.setHeader('Content-Type', 'application/json');
|
|
response.end(JSON.stringify(page));
|
|
return;
|
|
}
|
|
const escaped = JSON.stringify(page)
|
|
.replaceAll('&', '&')
|
|
.replaceAll('"', '"')
|
|
.replaceAll('<', '<');
|
|
response.setHeader('Content-Type', 'text/html');
|
|
response.end(
|
|
await server.transformIndexHtml(
|
|
request.url,
|
|
'<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"></head><body><div id="app" data-page="' +
|
|
escaped +
|
|
'"></div><script type="module" src="/tests/Fixtures/dashboard-preview.mjs"></script></body></html>',
|
|
),
|
|
);
|
|
});
|
|
await server.listen();
|
|
console.log('Dashboard fixture ready at http://127.0.0.1:4180/dashboard');
|
|
} else {
|
|
try {
|
|
const { createLocalization } = await server.ssrLoadModule(
|
|
'/resources/js/lib/localization.ts',
|
|
);
|
|
const { createAppearance } = await server.ssrLoadModule(
|
|
'/resources/js/composables/useAppearance.ts',
|
|
);
|
|
const { default: Dashboard } = await server.ssrLoadModule(
|
|
'/resources/js/pages/Dashboard.vue',
|
|
);
|
|
const render = async (url) => {
|
|
const response = await createInertiaApp({
|
|
page: makePage(url),
|
|
resolve: () => Dashboard,
|
|
render: renderToString,
|
|
setup: ({ App, props, plugin }) =>
|
|
createSSRApp({ render: () => h(App, props) })
|
|
.use(plugin)
|
|
.use(createLocalization())
|
|
.use(createAppearance('light')),
|
|
});
|
|
return response.body.split('<main')[1].split('</main>')[0];
|
|
};
|
|
|
|
const dashboard = await render('/dashboard');
|
|
assert.match(dashboard, /Welcome back, Alex Morgan/);
|
|
assert.match(dashboard, /Assigned tickets/);
|
|
assert.match(dashboard, /Projects with assigned work/);
|
|
assert.match(dashboard, /Blocked tickets/);
|
|
assert.match(dashboard, /Ship the dashboard with real assigned work/);
|
|
assert.match(dashboard, /Resolve the deployment blocker/);
|
|
assert.match(dashboard, /href="\/projects\/7\/tickets\/42"/);
|
|
assert.match(dashboard, /href="\/projects\/9"/);
|
|
assert.doesNotMatch(
|
|
dashboard,
|
|
/API-integration|Finished this week|Recent activity|PlaceholderPattern/,
|
|
);
|
|
|
|
const empty = await render('/dashboard?empty');
|
|
assert.match(empty, /No tickets assigned to you/);
|
|
assert.match(empty, /href="\/projects"/);
|
|
assert.doesNotMatch(empty, /ENG-42|OPS-12|<article/);
|
|
|
|
console.log('Dashboard behavior checks passed.');
|
|
} finally {
|
|
await server.close();
|
|
}
|
|
}
|