Skip to content

Commit

Permalink
Merge pull request #3475 from owid/add-api-tests
Browse files Browse the repository at this point in the history
Add a setup for tests for the admin rest api
  • Loading branch information
danyx23 authored Jul 11, 2024
2 parents f466bca + 6008926 commit bb1dd7b
Show file tree
Hide file tree
Showing 16 changed files with 3,147 additions and 267 deletions.
195 changes: 188 additions & 7 deletions adminSiteServer/app.test.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,199 @@
import { OwidAdminApp } from "./app.js"
import { google } from "googleapis"
import { jest } from "@jest/globals"
// Mock the google docs api to retrieve files from the test-files directory
// AFAICT, we have to do this directly after the import
// and before any other code that might import googleapis
jest.mock("googleapis", () => {
const originalModule: any = jest.requireActual("googleapis")

return {
...originalModule,
google: {
...originalModule.google,
docs: jest.fn(() => ({
documents: {
get: jest.fn(({ documentId }) => {
// This is a bit hacky and assumes we are running from inside
// the itsJustJavascript directory - I couldn't find a better way
// to get the workspace root directory here
const unparsed = fs.readFileSync(
path.join(
__dirname,
"..",
"..",
"adminSiteServer",
"test-files",
`${documentId}.json`
),
"utf8"
)
const data = JSON.parse(unparsed)
return Promise.resolve(data)
}),
},
})),
},
}
})

import { OwidAdminApp } from "./appClass.js"

import { logInAsUser } from "./authentication.js"
import knex, { Knex } from "knex"
import { dbTestConfig } from "../db/tests/dbTestConfig.js"
import {
TransactionCloseMode,
knexRaw,
knexReadWriteTransaction,
setKnexInstance,
} from "../db/db.js"
import { cleanTestDb } from "../db/tests/testHelpers.js"
import { ChartsTableName } from "@ourworldindata/types"
import path from "path"
import fs from "fs"

jest.setTimeout(10000) // wait for up to 10s for the app server to start
let testKnexInstance: Knex<any, unknown[]> | undefined = undefined
let serverKnexInstance: Knex<any, unknown[]> | undefined = undefined
let app: OwidAdminApp | undefined = undefined
let cookieId: string = ""

beforeAll(async () => {
// dummy use of google docs so that when we import the google
// docs above to mock it, prettier will not complain about an unused import
const _ = google.docs
testKnexInstance = knex(dbTestConfig)
serverKnexInstance = knex(dbTestConfig)
const dataSpec = {
users: [
{
email: "[email protected]",
fullName: "Admin",
password: "admin",
createdAt: new Date(),
updatedAt: new Date(),
},
],
}

describe(OwidAdminApp, () => {
const app = new OwidAdminApp({ isDev: true, gitCmsDir: "", quiet: true })
await cleanTestDb(testKnexInstance)
for (const [tableName, tableData] of Object.entries(dataSpec)) {
await testKnexInstance(tableName).insert(tableData)
}

setKnexInstance(serverKnexInstance!)

app = new OwidAdminApp({ isDev: true, gitCmsDir: "", quiet: true })
await app.startListening(8765, "localhost")
cookieId = (
await logInAsUser({
email: "[email protected]",
id: 1,
})
).id
})

async function cleanupDb() {
// We leave the user in the database for other tests to use
// For other cases it is good to drop any rows created in the test
await knexReadWriteTransaction(
async (trx) => {
await knexRaw(trx, `DELETE FROM posts_gdocs`, [])
},
TransactionCloseMode.KeepOpen,
testKnexInstance
)
}

afterAll((done: any) => {
void cleanupDb()
.then(() =>
Promise.allSettled([
app?.stopListening(),
testKnexInstance?.destroy(),
serverKnexInstance?.destroy(),
])
)
.then(() => done())
})

async function getCountForTable(tableName: string): Promise<number> {
// This helper simply checks how many rows are in a table. I can be used
// for super simple asserts to verify if a row was created or deleted.
const count = await testKnexInstance!.table(tableName).count()
return count[0]["count(*)"] as number
}

describe("OwidAdminApp", () => {
it("should be able to create an app", () => {
expect(app).toBeTruthy()
expect(app!.server).toBeTruthy()
})

it("should be able to start the app", async () => {
await app.startListening(8765, "localhost")
expect(app.server).toBeTruthy()
await app.stopListening()
it("should be able to fetch the version from the server", async () => {
const nodeVersion = await fetch(
"http://localhost:8765/admin/nodeVersion",
{
headers: { cookie: `sessionid=${cookieId}` },
}
)
expect(nodeVersion.status).toBe(200)
const text = await nodeVersion.text()
expect(text).toBe("v18.16.0")
})

it("should be able to add a new chart via the api", async () => {
const chartCount = await getCountForTable(ChartsTableName)
expect(chartCount).toBe(0)
const response = await fetch("http://localhost:8765/admin/api/charts", {
method: "POST",
headers: {
"Content-Type": "application/json",
cookie: `sessionid=${cookieId}`,
},
body: JSON.stringify({
slug: "test-chart",
config: {
title: "Test chart",
type: "LineChart",
},
}),
})
expect(response.status).toBe(200)
const text = await response.json()
expect(text.success).toBe(true)

const chartCountAfter = await getCountForTable(ChartsTableName)
expect(chartCountAfter).toBe(1)
})

it("should be able to create a GDoc article", async () => {
const gdocId = "gdoc-test-create-1"
const response = await fetch(
`http://localhost:8765/admin/api/gdocs/${gdocId}`,
{
method: "PUT",
headers: {
"Content-Type": "application/json",
cookie: `sessionid=${cookieId}`,
},
}
)
expect(response.status).toBe(200)

const text = await response.json()
expect(text.id).toBe(gdocId)

// Fetch the GDoc to verify it was created
const gdocResponse = await fetch(
`http://localhost:8765/admin/api/gdocs/${gdocId}`,
{
headers: { cookie: `sessionid=${cookieId}` },
}
)
expect(gdocResponse.status).toBe(200)
const gdoc = await gdocResponse.json()
expect(gdoc.id).toBe(gdocId)
expect(gdoc.content.title).toBe("Basic article")
})
})
Loading

0 comments on commit bb1dd7b

Please sign in to comment.