Skip to content

Commit

Permalink
add next v9 test and improve fixture tooling (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ethan-Arrowood authored Dec 6, 2024
1 parent c14f21e commit 0ab5f1c
Show file tree
Hide file tree
Showing 19 changed files with 284 additions and 134 deletions.
1 change: 1 addition & 0 deletions fixtures/next-9/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package-lock=false
3 changes: 3 additions & 0 deletions fixtures/next-9/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
'@harperdb/nextjs':
package: '@harperdb/nextjs'
files: '/*'
1 change: 1 addition & 0 deletions fixtures/next-9/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = {};
17 changes: 17 additions & 0 deletions fixtures/next-9/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "next-9",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"postinstall": "npm link @harperdb/nextjs"
},
"dependencies": {
"@harperdb/nextjs": "*",
"next": "^9.5.5",
"react": "^16.14.0",
"react-dom": "^16.14.0"
}
}
12 changes: 12 additions & 0 deletions fixtures/next-9/pages/_app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Head from 'next/head';

export default function App({ Component, pageProps }) {
return (
<>
<Head>
<title>HarperDB - Next.js v9 App</title>
</Head>
<Component {...pageProps} />
</>
);
}
15 changes: 15 additions & 0 deletions fixtures/next-9/pages/_document.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Document, { Html, Head, Main, NextScript } from 'next/document';

export default class MyDocument extends Document {
render() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
10 changes: 10 additions & 0 deletions fixtures/next-9/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Link from 'next/link';

export default function Index() {
return (
<div>
<h1>Next.js v9</h1>
<Link href="/page-2">Page 2</Link>
</div>
);
}
10 changes: 10 additions & 0 deletions fixtures/next-9/pages/page-2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Link from 'next/link';

export default function Page2() {
return (
<div>
<h1>Page 2</h1>
<Link href="/">Home</Link>
</div>
);
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
"format:check": "npm run format -- --check",
"format:fix": "npm run format -- --write",
"pretest": "node util/scripts/pretest.js",
"test": "playwright test --workers 3"
"test": "playwright test --workers 3",
"build-fixture": "node util/scripts/build-fixture-cli.js"
},
"dependencies": {
"shell-quote": "^1.8.1"
Expand Down
12 changes: 5 additions & 7 deletions playwright.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { defineConfig, devices } from '@playwright/test';

const NEXT_MAJORS = ['13', '14', '15'];
const NODE_MAJORS = ['18', '20', '22'];
import { VERSION_MATRIX } from './util/constants-and-names';

export default defineConfig({
testDir: 'test',
Expand All @@ -12,11 +10,11 @@ export default defineConfig({
expect: {
timeout: 30000,
},
projects: NEXT_MAJORS.flatMap((nextMajor) =>
NODE_MAJORS.map((nodeMajor) => ({
projects: [
...VERSION_MATRIX.map(([nextMajor, nodeMajor]) => ({
name: `Next.js v${nextMajor} - Node.js v${nodeMajor}`,
use: { versions: { nextMajor, nodeMajor }, ...devices['Desktop Chrome'] },
testMatch: [`test/next-${nextMajor}.test.js`],
}))
),
})),
],
});
19 changes: 19 additions & 0 deletions test/next-9.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { test, expect } from '../util/test-fixture.js';

test.describe.configure({ mode: 'serial' });

test('home page', async ({ nextApp, page }) => {
await page.goto(nextApp.rest.toString());
await expect(page.locator('h1')).toHaveText('Next.js v9');
});

test('title', async ({ nextApp, page }) => {
await page.goto(nextApp.rest.toString());
await expect(page).toHaveTitle('HarperDB - Next.js v9 App');
});

test('page 2', async ({ nextApp, page }) => {
await page.goto(nextApp.rest.toString());
await page.locator('a').click();
await expect(page.locator('h1')).toHaveText('Page 2');
});
70 changes: 70 additions & 0 deletions util/build-fixture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { spawn } from 'node:child_process';
import { join } from 'node:path';
import { DEBUG, ROOT, getNodeBaseImageName, getNextImageName } from './constants-and-names.js';
import { CONTAINER_ENGINE } from './container-engine.js';
import { CollectedTransform } from './collected-transform.js';

function validateResult(result) {
const success = result.code === 0;

if (DEBUG || !success) {
console.log(`Image \x1b[94m${result.name}\x1b[0m build process exited with: \x1b[35m${result.code}\x1b[0m\n`);
result.stdout !== '' && console.log('\x1b[32mstdout\x1b[0m:\n' + result.stdout + '\n');
result.stderr !== '' && console.log('\x1b[31mstderr\x1b[0m:\n' + result.stderr + '\n');
}

if (!success) {
process.exit(1);
}
}

function build(name, args, options = {}) {
return new Promise((resolve, reject) => {
const buildProcess = spawn(CONTAINER_ENGINE, args, { cwd: ROOT, stdio: ['ignore', 'pipe', 'pipe'], ...options });

const collectedStdout = buildProcess.stdout.pipe(new CollectedTransform());
const collectedStderr = buildProcess.stderr.pipe(new CollectedTransform());

buildProcess.on('error', reject);
buildProcess.on('close', (code) =>
resolve({
name,
code,
stdout: collectedStdout.output,
stderr: collectedStderr.output,
})
);
});
}

export function buildNodeImage(nodeMajor, validate = true) {
const buildPromise = build(getNodeBaseImageName(nodeMajor), [
'build',
'--build-arg',
`NODE_MAJOR=${nodeMajor}`,
'-t',
getNodeBaseImageName(nodeMajor),
'-f',
join(ROOT, 'util', 'docker', 'base.dockerfile'),
ROOT,
]);

return validate ? buildPromise.then(validateResult) : buildPromise;
}

export function buildNextImage(nextMajor, nodeMajor, validate = true) {
const buildPromise = build(getNextImageName(nextMajor, nodeMajor), [
'build',
'--build-arg',
`BASE_IMAGE=${getNodeBaseImageName(nodeMajor)}`,
'--build-arg',
`NEXT_MAJOR=${nextMajor}`,
'-t',
getNextImageName(nextMajor, nodeMajor),
'-f',
join(ROOT, 'util', 'docker', 'next.dockerfile'),
ROOT,
]);

return validate ? buildPromise.then(validateResult) : buildPromise;
}
27 changes: 0 additions & 27 deletions util/cache-bust.js

This file was deleted.

24 changes: 21 additions & 3 deletions util/constants-and-names.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
import { join } from 'node:path';

export const ROOT = join(import.meta.dirname, '..');
export const DEBUG = process.env.DEBUG === '1';

export const NEXT_MAJORS = ['13', '14', '15'];
export const ROOT = join(import.meta.dirname, '..');

export const NODE_MAJORS = ['18', '20', '22'];
export const VERSION_MATRIX = [
// Next.js v9
['9', '16'],
// Next.js v13
['13', '18'],
['13', '20'],
['13', '22'],
// Next.js v14
['14', '18'],
['14', '20'],
['14', '22'],
// Next.js v15
['15', '18'],
['15', '20'],
['15', '22'],
];

export const NEXT_MAJORS = new Set(VERSION_MATRIX.map(([nextMajor]) => nextMajor));
export const NODE_MAJORS = new Set(VERSION_MATRIX.map(([_, nodeMajor]) => nodeMajor));

export const PORTS = ['9925', '9926'];

Expand Down
25 changes: 15 additions & 10 deletions util/docker/base.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@

ARG NODE_MAJOR

FROM node:${NODE_MAJOR}
FROM docker.io/node:${NODE_MAJOR}-slim

EXPOSE 9925 9926

# Install utilities for the container
RUN apt-get update && apt-get install -y \
curl \
# List of tools to install
# curl \
# Clean Up
&& rm -rf /var/lib/apt/lists/*

# Install HarperDB Globally
RUN npm install -g harperdb
RUN npm install -g harperdb@4.4.8

# Set HarperDB Environment Variables
ENV TC_AGREEMENT=yes
Expand All @@ -23,25 +28,25 @@ ENV THREADS_COUNT=1
ENV LOGGING_STDSTREAMS=true
ENV LOGGING_LEVEL=debug

# Create components directory
RUN mkdir -p /hdb/components
RUN harperdb start

# Add base component
COPY /fixtures/harperdb-base-component /hdb/components/harperdb-base-component

# Create the @harperdb/nextjs module directory so it can be linked locally
RUN mkdir -p /@harperdb/nextjs

# Cache Bust copying project files
ARG CACHE_BUST
RUN echo "${CACHE_BUST}"
COPY config.yaml extension.js cli.js package.json /@harperdb/nextjs/

WORKDIR /@harperdb/nextjs

# Install dependencies for the @harperdb/nextjs module
RUN npm install
RUN npm install --omit=dev

# Create link to the @harperdb/nextjs module
RUN npm link

WORKDIR /
WORKDIR /

# By default, run HarperDB when the container starts. This can be overridden by passing a different command to the container, or using a new CMD in a child Dockerfile.
CMD harperdb run
8 changes: 2 additions & 6 deletions util/docker/next.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,11 @@ FROM ${BASE_IMAGE}

ARG NEXT_MAJOR

ARG CACHE_BUST
RUN echo "${CACHE_BUST}"
COPY fixtures/next-${NEXT_MAJOR} /hdb/components/next-${NEXT_MAJOR}

WORKDIR /hdb/components/next-${NEXT_MAJOR}

# Fixtures should automatically link the @harperdb/nextjs module via their postinstall script.
RUN npm install

WORKDIR /

EXPOSE 9925 9926

CMD ["harperdb", "run"]
15 changes: 11 additions & 4 deletions util/fixture.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
import { spawn, spawnSync } from 'node:child_process';
import { Transform } from 'node:stream';

import { getNextImageName, getNextContainerName, NEXT_MAJORS, NODE_MAJORS, PORTS } from './constants-and-names.js';
import {
getNextImageName,
getNextContainerName,
NEXT_MAJORS,
NODE_MAJORS,
PORTS,
DEBUG,
} from './constants-and-names.js';
import { CONTAINER_ENGINE } from './container-engine.js';
import { CollectedTransform } from './collected-transform.js';

export class Fixture {
constructor({ autoSetup = true, debug = false, nextMajor, nodeMajor }) {
if (!NEXT_MAJORS.includes(nextMajor)) {
if (!NEXT_MAJORS.has(nextMajor)) {
throw new Error(`nextMajor must be one of ${NEXT_MAJORS.join(', ')}`);
}
this.nextMajor = nextMajor;

if (!NODE_MAJORS.includes(nodeMajor)) {
if (!NODE_MAJORS.has(nodeMajor)) {
throw new Error(`nodeMajor must be one of ${NODE_MAJORS.join(', ')}`);
}
this.nodeMajor = nodeMajor;

this.debug = debug || process.env.DEBUG === '1';
this.debug = debug || DEBUG;

this.imageName = getNextImageName(nextMajor, nodeMajor);
this.containerName = getNextContainerName(nextMajor, nodeMajor);
Expand Down
Loading

0 comments on commit 0ab5f1c

Please sign in to comment.