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

chore(api-server): improve tests #9325

Merged
merged 9 commits into from
Oct 24, 2023
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
41 changes: 41 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -559,3 +559,44 @@ jobs:

steps:
- run: echo "RSC smoke tests mock"

server-tests:
needs: check

name: 📡🔁 server tests / node 18 latest
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: ⬢ Set up Node.js
uses: actions/setup-node@v3
with:
node-version: 18

- name: 🐈 Set up yarn cache
uses: ./.github/actions/set-up-yarn-cache

- name: 🐈 Yarn install
run: yarn install --inline-builds
env:
GITHUB_TOKEN: ${{ github.token }}

- name: 🔨 Build
run: yarn build

- name: 🧪 Test
run: yarn jest server.test.ts
working-directory: ./tasks/server-tests
env:
REDWOOD_DISABLE_TELEMETRY: 1

server-tests-docs:
needs: only-doc-changes
if: needs.only-doc-changes.outputs.only-doc-changes == 'true'

name: 📡🔁 server tests / node 18 latest
runs-on: ubuntu-latest

steps:
- run: echo "Only doc changes"
2 changes: 2 additions & 0 deletions packages/api-server/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
!src/__tests__/fixtures/**/dist
coverage
105 changes: 105 additions & 0 deletions packages/api-server/dist.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import fs from 'fs'
import path from 'path'

const distPath = path.join(__dirname, 'dist')
const packageConfig = JSON.parse(fs.readFileSync('./package.json', 'utf-8'))

describe('dist', () => {
it("shouldn't have the __tests__ directory", () => {
expect(fs.existsSync(path.join(distPath, '__tests__'))).toEqual(false)
})

// The way this package was written, you can't just import it. It expects to be in a Redwood project.
it('fails if imported outside a Redwood app', async () => {
try {
await import(path.join(distPath, 'cliHandlers.js'))
} catch (e) {
expect(e.message).toMatchInlineSnapshot(
`"Could not find a "redwood.toml" file, are you sure you're in a Redwood project?"`
)
}
})

it('exports CLI options and handlers', async () => {
const original_RWJS_CWD = process.env.RWJS_CWD

process.env.RWJS_CWD = path.join(
__dirname,
'src/__tests__/fixtures/redwood-app'
)

const mod = await import(
path.resolve(distPath, packageConfig.main.replace('dist/', ''))
)

expect(mod).toMatchInlineSnapshot(`
{
"apiCliOptions": {
"apiRootPath": {
"alias": [
"rootPath",
"root-path",
],
"coerce": [Function],
"default": "/",
"desc": "Root path where your api functions are served",
"type": "string",
},
"loadEnvFiles": {
"default": false,
"description": "Load .env and .env.defaults files",
"type": "boolean",
},
"port": {
"alias": "p",
"default": 8911,
"type": "number",
},
"socket": {
"type": "string",
},
},
"apiServerHandler": [Function],
"bothServerHandler": [Function],
"commonOptions": {
"port": {
"alias": "p",
"default": 8910,
"type": "number",
},
"socket": {
"type": "string",
},
},
"webCliOptions": {
"apiHost": {
"alias": "api-host",
"desc": "Forward requests from the apiUrl, defined in redwood.toml to this host",
"type": "string",
},
"port": {
"alias": "p",
"default": 8910,
"type": "number",
},
"socket": {
"type": "string",
},
},
"webServerHandler": [Function],
}
`)

process.env.RWJS_CWD = original_RWJS_CWD
})

it('ships three bins', () => {
expect(packageConfig.bin).toMatchInlineSnapshot(`
{
"rw-api-server-watch": "./dist/watch.js",
"rw-log-formatter": "./dist/logFormatter/bin.js",
"rw-server": "./dist/index.js",
}
`)
})
})
7 changes: 7 additions & 0 deletions packages/api-server/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/** @type {import('jest').Config} */
const config = {
testPathIgnorePatterns: ['/node_modules/', '/fixtures/'],
coveragePathIgnorePatterns: ['<rootDir>/dist/', '<rootDir>/src/__tests__/'],
}

module.exports = config
2 changes: 1 addition & 1 deletion packages/api-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx\" --ignore dist --exec \"yarn build && yarn fix:permissions\"",
"fix:permissions": "chmod +x dist/index.js; chmod +x dist/watch.js",
"prepublishOnly": "NODE_ENV=production yarn build",
"test": "jest src",
"test": "jest",
"test:watch": "yarn test --watch"
},
"dependencies": {
Expand Down
103 changes: 103 additions & 0 deletions packages/api-server/src/__tests__/fastify.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import fastify from 'fastify'
import { vol } from 'memfs'

import { createFastifyInstance, DEFAULT_OPTIONS } from '../fastify'

// We'll be testing how fastify is instantiated, so we'll mock it here.
jest.mock('fastify', () => {
return jest.fn(() => {
return {
register: () => {},
}
})
})

// Suppress terminal logging.
console.log = jest.fn()

// Set up RWJS_CWD.
let original_RWJS_CWD
const FIXTURE_PATH = '/redwood-app'

beforeAll(() => {
original_RWJS_CWD = process.env.RWJS_CWD
process.env.RWJS_CWD = FIXTURE_PATH
})

afterAll(() => {
process.env.RWJS_CWD = original_RWJS_CWD
})

// Mock server.config.js to test instantiating fastify with user config.
jest.mock('fs', () => require('memfs').fs)

afterEach(() => {
vol.reset()
})

const userConfig = {
requestTimeout: 25_000,
}

jest.mock(
'/redwood-app/api/server.config.js',
() => {
return {
config: userConfig,
}
},
{
virtual: true,
}
)

jest.mock(
'\\redwood-app\\api\\server.config.js',
() => {
return {
config: userConfig,
}
},
{
virtual: true,
}
)

describe('createFastifyInstance', () => {
it('instantiates a fastify instance with default config', () => {
vol.fromNestedJSON(
{
'redwood.toml': '',
},
FIXTURE_PATH
)

createFastifyInstance()
expect(fastify).toHaveBeenCalledWith(DEFAULT_OPTIONS)
})

it("instantiates a fastify instance with the user's configuration if available", () => {
vol.fromNestedJSON(
{
'redwood.toml': '',
api: {
'server.config.js': '',
},
},
FIXTURE_PATH
)

createFastifyInstance()
expect(fastify).toHaveBeenCalledWith(userConfig)
})
})

test('DEFAULT_OPTIONS configures the log level based on NODE_ENV', () => {
expect(DEFAULT_OPTIONS).toMatchInlineSnapshot(`
{
"logger": {
"level": "info",
},
}
`)
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# This file contains the configuration settings for your Redwood app.
# This file is also what makes your Redwood app a Redwood app.
# If you remove it and try to run `yarn rw dev`, you'll get an error.
#
# For the full list of options, see the "App Configuration: redwood.toml" doc:
# https://redwoodjs.com/docs/app-configuration-redwood-toml

[web]
title = "Redwood App"
port = 8910
apiUrl = "/.redwood/functions" # You can customize graphql and dbauth urls individually too: see https://redwoodjs.com/docs/app-configuration-redwood-toml#api-paths
includeEnvironmentVariables = [
# Add any ENV vars that should be available to the web side to this array
# See https://redwoodjs.com/docs/environment-variables#web
]
[api]
port = 8911
[browser]
open = true
[notifications]
versionUpdates = ["latest"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en">

<head>
<script defer="defer" src="/assets/AboutPage-7ec0f8df.js" type="module"></script>
<title data-rh="true">Redwood App | Redwood App</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/png" href="/favicon.png">
<script type="module" crossorigin="" src="/assets/index-ff057e8f.js"></script>
<link rel="stylesheet" href="/assets/index-613d397d.css">
<script> globalThis.__REDWOOD__APOLLO_STATE = {}</script>
</head>

<body>
<!-- Please keep this div empty -->
<div id="redwood-app">
<header class="relative flex items-center justify-between bg-blue-700 px-8 py-4 text-white">
<h1 class="text-3xl font-semibold tracking-tight"><a href="/"
class="text-blue-400 transition duration-100 hover:text-blue-100">Redwood Blog</a></h1>
<nav>
<ul class="relative flex items-center font-light">
<li><a href="/about" class="rounded px-4 py-2 transition duration-100 hover:bg-blue-600">About</a></li>
<li><a href="/contact" class="rounded px-4 py-2 transition duration-100 hover:bg-blue-600">Contact Us</a></li>
<li><a href="/posts" class="rounded px-4 py-2 transition duration-100 hover:bg-blue-600">Admin</a></li>
<li><a href="/login" class="rounded px-4 py-2 transition duration-100 hover:bg-blue-600">Log In</a></li>
</ul>
</nav>
</header>
<main class="mx-auto mt-3 max-w-4xl rounded-b bg-white p-12 shadow-lg"><!--$-->
<p class="font-light">This site was created to demonstrate my mastery of Redwood: Look on my works, ye mighty, and
despair!</p>
<div id="redwood-announcer"
style="position:absolute;top:0;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0"
role="alert" aria-live="assertive" aria-atomic="true"></div><!--/$-->
</main>
</div>
</body>

</html>
Loading