import assert from 'node:assert/strict'; import process from 'node:process'; import { fileURLToPath } from 'node:url'; import vue from '@vitejs/plugin-vue'; import tailwind from '@tailwindcss/vite'; import { createServer } from 'vite'; import { createSSRApp, h } from 'vue'; import { renderToString } from 'vue/server-renderer'; import { createInertiaApp } from '@inertiajs/vue3'; const serve = process.argv.includes('--serve'); const server = await createServer({ configFile: false, cacheDir: 'node_modules/.vite/project-overview-fixture', plugins: [vue(), ...(serve ? [tailwind()] : [])], resolve: { alias: { '@': fileURLToPath(new URL('../../resources/js', import.meta.url)), }, }, server: serve ? { host: '127.0.0.1', port: 4178, strictPort: true, hmr: false } : { middlewareMode: true, hmr: false, watch: null }, appType: 'custom', }); const project = { id: 7, key: 'ENG', name: 'Engineering · Platform and developer experience', }; const secondProject = { id: 8, key: 'OPS', name: 'Operations' }; const templateState = { inheritsFromTemplate: true, templateName: 'Team baseline', inheritedAreas: [{ value: 'board_columns', label: 'Board columns' }], overriddenAreas: [{ value: 'ticket_types', label: 'Ticket types' }], }; function makePage( url, { manage = false, create = false, empty = false, template = false, status = null, } = {}, ) { const path = new URL(url, 'http://localhost').pathname; const isIndex = path === '/projects'; const isShow = path === '/projects/7'; return { component: isIndex ? 'Index' : isShow ? 'Show' : 'Destination', url, version: null, clearHistory: false, encryptHistory: false, props: { name: 'KanbanGit', errors: {}, sidebarOpen: true, auth: { user: { id: 1, name: 'Alex Morgan', email: 'alex@example.test', avatar: null, }, permissions: { globalAdmin: false, projectCreate: create, canManageTeams: false, }, }, navigation: { project: isIndex ? null : { ...project, canManage: manage, canCreateTickets: manage, }, }, ...(isIndex ? { projects: empty ? [] : [project, secondProject], status } : { project, canManageAccess: manage, templateState: template ? templateState : null, }), }, }; } if (serve) { // Isolated transport for real Vue pages. PHPUnit covers actual permissions and resources. server.middlewares.use(async (request, response, next) => { const url = new URL(request.url, 'http://localhost'); if (!url.pathname.startsWith('/projects')) { return next(); } const role = request.headers.cookie?.match( /project_test_role=(\w+)/, )?.[1]; const page = makePage(request.url, { manage: role === 'admin', create: role === 'creator', empty: url.searchParams.has('empty'), template: url.searchParams.has('template'), }); 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, '
', ), ); }); await server.listen(); console.log( 'Project overview fixture ready at http://127.0.0.1:4178/projects', ); } else { try { const { createLocalization } = await server.ssrLoadModule( '/resources/js/lib/localization.ts', ); const { createAppearance } = await server.ssrLoadModule( '/resources/js/composables/useAppearance.ts', ); const { en } = await server.ssrLoadModule( '/resources/js/locales/en.ts', ); const pages = Object.fromEntries( await Promise.all( ['Index', 'Show'].map(async (name) => [ name, ( await server.ssrLoadModule( `/resources/js/pages/projects/${name}.vue`, ) ).default, ]), ), ); const render = async ( url, options = {}, locale = createLocalization(), ) => { const response = await createInertiaApp({ page: makePage(url, options), resolve: (name) => pages[name], render: renderToString, setup: ({ App, props, plugin }) => createSSRApp({ render: () => h(App, props) }) .use(plugin) .use(locale) .use(createAppearance('light')), }); return response.body.split('