Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: replace jest with vitest #449

Merged
merged 2 commits into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
name: 'Test'
on:
pull_request:
branches: [main]
push:
branches: [main]

Expand All @@ -21,5 +20,5 @@ jobs:
- name: Install and build
run: |
npm ci
- name: Run Jest
- name: Run Tests
run: npm run test
1 change: 0 additions & 1 deletion .jest/dirname.cjs

This file was deleted.

236 changes: 123 additions & 113 deletions __tests__/integration.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,153 +3,163 @@
* SPDX-License-Identifier: MPL-2.0
*/

import { jest } from '@jest/globals'
import { Server } from 'http'
import * as cheerio from 'cheerio'

import {
buildFixture,
createDescribe,
readOutputFile,
serveStatic,
startDevServer,
stopDevServer,
} from '../.jest/utils'
createTmpTestDir,
cleanupTmpTestDir,
} from './utils'
import { ChildProcess } from 'child_process'
import { vi, describe, test, expect, beforeAll } from 'vitest'
import puppeteer, { type Browser } from 'puppeteer'

vi.setConfig({ testTimeout: 30000, hookTimeout: 30000 })

describe('hydration - production', () => {
let tmpDir: string
let browser: Browser

beforeAll(async () => {
tmpDir = await createTmpTestDir('basic')
browser = await puppeteer.launch()
buildFixture(tmpDir)

return async () => {
await browser.close()
await cleanupTmpTestDir(tmpDir)
}
})

test('server rendered output', async () => {
const result = await readOutputFile(tmpDir, 'index')
const $ = cheerio.load(result)

const htmlOutput = $('#__next').html()

// server renders correctly
expect(htmlOutput).toContain(`<h1>foo</h1>`)
expect(htmlOutput).toContain(`<h2>Headline</h2>`)
expect(htmlOutput).toContain(`<p>hello <!-- -->jeff</p>`)
expect(htmlOutput).toContain(`<button>Count: <!-- -->0</button>`)
expect($('.context').text()).toBe('Context value: "foo"')
expect(htmlOutput).toContain(
`<p>Some <strong class=\"custom-strong\">markdown</strong> content</p>`
)
expect(htmlOutput).toContain(
`<div class=\"alert alert-warning g-type-body\"><p>Alert</p></div>`
)
})

jest.setTimeout(30000)

createDescribe(
'hydration - production',
{ fixture: 'basic' },
({ dir, browser }) => {
beforeAll(() => {
buildFixture(dir())
})

test('server rendered output', () => {
const result = readOutputFile(dir(), 'index')
const $ = cheerio.load(result)

const htmlOutput = $('#__next').html()

// server renders correctly
expect(htmlOutput).toContain(`<h1>foo</h1>`)
expect(htmlOutput).toContain(`<h2>Headline</h2>`)
expect(htmlOutput).toContain(`<p>hello <!-- -->jeff</p>`)
expect(htmlOutput).toContain(`<button>Count: <!-- -->0</button>`)
expect($('.context').text()).toBe('Context value: "foo"')
expect(htmlOutput).toContain(
`<p>Some <strong class=\"custom-strong\">markdown</strong> content</p>`
)
expect(htmlOutput).toContain(
`<div class=\"alert alert-warning g-type-body\"><p>Alert</p></div>`
)
})

test('rehydrates correctly in browser', async () => {
// hydrates correctly
let server: Server
const page = await browser().newPage()
page.on('console', (msg) => console.log(msg.text()))
server = await serveStatic(dir())
test('rehydrates correctly in browser', async () => {
// hydrates correctly
let server: Server
const page = await browser.newPage()
page.on('console', (msg) => console.log(msg.text()))
server = await serveStatic(tmpDir)

await page.goto('http://localhost:1235')
await page.goto('http://localhost:1235')

// @ts-expect-error
await page.waitForFunction(() => Boolean(window.__NEXT_HYDRATED))
// @ts-expect-error
await page.waitForFunction(() => Boolean(window.__NEXT_HYDRATED))

await page.waitForSelector('button')
await page.waitForSelector('button')

// click the button
await page.click('button')
// click the button
await page.click('button')

// wait for react to render
await page.waitForFunction(() => {
return document.querySelector('button')?.innerText === 'Count: 1'
})
// wait for react to render
await page.waitForFunction(() => {
return document.querySelector('button')?.innerText === 'Count: 1'
})

// pull text for elements we're testing hydrate on
const contextElementText = await page.$eval(
'.context',
// @ts-expect-error -- el is typed as Element, but reasonable to assume it is an HTMLElement at this point
(el) => el.innerText
)
// pull text for elements we're testing hydrate on
const contextElementText = await page.$eval(
'.context',
// @ts-expect-error -- el is typed as Element, but reasonable to assume it is an HTMLElement at this point
const buttonText = await page.$eval('button', (el) => el.innerText)
(el) => el.innerText
)
// @ts-expect-error -- el is typed as Element, but reasonable to assume it is an HTMLElement at this point
const buttonText = await page.$eval('button', (el) => el.innerText)

expect(buttonText).toEqual('Count: 1')
expect(contextElementText).toEqual('Context value: "bar"')
expect(buttonText).toEqual('Count: 1')
expect(contextElementText).toEqual('Context value: "bar"')

// close the browser and dev server
await new Promise((resolve) => server.close(resolve))
})
}
)
// close the browser and dev server
await new Promise((resolve) => server.close(resolve))
})
})

createDescribe(
'hydration - dev server',
{ fixture: 'basic' },
({ dir, browser }) => {
let childProcess: ChildProcess
describe('hydration - dev server', () => {
let tmpDir: string
let browser: Browser
let childProcess: ChildProcess

beforeAll(async () => {
childProcess = await startDevServer(dir())
})
beforeAll(async () => {
tmpDir = await createTmpTestDir('basic')
browser = await puppeteer.launch()
childProcess = await startDevServer(tmpDir)

afterAll(async () => {
// close the browser and dev server
return async () => {
await browser.close()
await stopDevServer(childProcess)
})
await cleanupTmpTestDir(tmpDir)
}
})

test('loads in development', async () => {
const page = await browser().newPage()
page.on('console', (msg) => console.log(msg.text()))
test('loads in development', async () => {
const page = await browser.newPage()
page.on('console', (msg) => console.log(msg.text()))

await page.goto('http://localhost:12333')
await page.goto('http://localhost:12333')

// @ts-expect-error
await page.waitForFunction(() => Boolean(window.__NEXT_HYDRATED))
// @ts-expect-error
await page.waitForFunction(() => Boolean(window.__NEXT_HYDRATED))

// @ts-expect-error -- el is typed as Element, but reasonable to assume it is an HTMLElement at this point
const headingText = await page.$eval('h1', (el) => el.innerText)
// @ts-expect-error -- el is typed as Element, but reasonable to assume it is an HTMLElement at this point
const headingText = await page.$eval('h1', (el) => el.innerText)

expect(headingText).toEqual('foo')
})
}
)
expect(headingText).toEqual('foo')
})
})

createDescribe(
'hydration - dev server - rsc',
{ fixture: 'rsc' },
({ dir, browser }) => {
let childProcess: ChildProcess
describe('hydration - dev server - rsc', () => {
let tmpDir: string
let browser: Browser
let childProcess: ChildProcess

beforeAll(async () => {
childProcess = await startDevServer(dir())
})
beforeAll(async () => {
tmpDir = await createTmpTestDir('rsc')
browser = await puppeteer.launch()
childProcess = await startDevServer(tmpDir)

afterAll(async () => {
// close the browser and dev server
return async () => {
await browser.close()
await stopDevServer(childProcess)
})

test.each(['/app-dir-mdx/mdxremote', '/app-dir-mdx/compile-mdx'])(
'%s',
async (path) => {
const page = await browser().newPage()
page.on('console', (msg) => console.log(msg.text()))
await cleanupTmpTestDir(tmpDir)
}
})

test.each(['/app-dir-mdx/mdxremote', '/app-dir-mdx/compile-mdx'])(
'%s',
async (path) => {
const page = await browser.newPage()
page.on('console', (msg) => console.log(msg.text()))

await page.goto(`http://localhost:12333${path}`)
await page.goto(`http://localhost:12333${path}`)

// @ts-expect-error
await page.waitForFunction(() => Boolean(window.__NEXT_HYDRATED))
// @ts-expect-error
await page.waitForFunction(() => Boolean(window.__NEXT_HYDRATED))

// @ts-expect-error -- el is typed as Element, but reasonable to assume it is an HTMLElement at this point
const headingText = await page.$eval('h1', (el) => el.innerText)
// @ts-expect-error -- el is typed as Element, but reasonable to assume it is an HTMLElement at this point
const headingText = await page.$eval('h1', (el) => el.innerText)

expect(headingText).toEqual('foo')
}
)
}
)
expect(headingText).toEqual('foo')
}
)
})
2 changes: 2 additions & 0 deletions __tests__/rsc.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

import { compileMDX } from '../rsc'

import { describe, test, expect } from 'vitest'

describe('compileMDX', () => {
test('frontmatter types', async () => {
const { frontmatter } = await compileMDX<{ title: string }>({
Expand Down
4 changes: 3 additions & 1 deletion __tests__/serialize.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import { VFile } from 'vfile'

import { MDXRemote } from '../'
import { serialize } from '../serialize'
import { renderStatic } from '../.jest/utils'
import { renderStatic } from './utils'

import { describe, test, expect } from 'vitest'

interface Frontmatter {
hello: string
Expand Down
Loading