add basic test db infra

Boom, now we can also run a clean MySQL test db on each test that wants it :)

the test I wrote as a sample is currently marked `it.skip` because it's not passing yet!
This commit is contained in:
Emi Matchu 2020-09-18 05:50:17 -07:00
parent 68b7beae1b
commit 07691a4e6b
7 changed files with 214 additions and 9 deletions

View file

@ -44,7 +44,7 @@
"mysql-dev": "mysql --host=localhost --user=impress_2020_dev --password=impress_2020_dev --database=impress_2020_dev", "mysql-dev": "mysql --host=localhost --user=impress_2020_dev --password=impress_2020_dev --database=impress_2020_dev",
"mysql-admin": "mysql --host=impress.openneo.net --user=matchu --password --database=openneo_impress", "mysql-admin": "mysql --host=impress.openneo.net --user=matchu --password --database=openneo_impress",
"mysqldump": "mysqldump --host=impress.openneo.net --user=$(dotenv -p IMPRESS_MYSQL_USER) --password=$(dotenv -p IMPRESS_MYSQL_PASSWORD) --column-statistics=0", "mysqldump": "mysqldump --host=impress.openneo.net --user=$(dotenv -p IMPRESS_MYSQL_USER) --password=$(dotenv -p IMPRESS_MYSQL_PASSWORD) --column-statistics=0",
"download-mysql-schema": "yarn --silent mysqldump openneo_impress species species_translations colors color_translations > scripts/setup-mysql-dev-constants.sql && yarn --silent mysqldump --no-data openneo_impress items > scripts/setup-mysql-dev-schema.sql", "download-mysql-schema": "yarn --silent mysqldump openneo_impress species species_translations colors color_translations > scripts/setup-mysql-dev-constants.sql && yarn --silent mysqldump --no-data openneo_impress items item_translations > scripts/setup-mysql-dev-schema.sql",
"setup-mysql": "yarn mysql-admin < scripts/setup-mysql.sql", "setup-mysql": "yarn mysql-admin < scripts/setup-mysql.sql",
"setup-mysql-dev": "yarn mysql-dev < scripts/setup-mysql-dev-constants.sql && yarn mysql-dev < scripts/setup-mysql-dev-schema.sql", "setup-mysql-dev": "yarn mysql-dev < scripts/setup-mysql-dev-constants.sql && yarn mysql-dev < scripts/setup-mysql-dev-schema.sql",
"build-cached-data": "node -r dotenv/config scripts/build-cached-data.js", "build-cached-data": "node -r dotenv/config scripts/build-cached-data.js",

View file

@ -133,4 +133,4 @@ UNLOCK TABLES;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2020-09-18 5:22:41 -- Dump completed on 2020-09-18 5:47:49

View file

@ -43,6 +43,30 @@ CREATE TABLE `items` (
KEY `objects_last_spidered` (`last_spidered`) KEY `objects_last_spidered` (`last_spidered`)
) ENGINE=InnoDB AUTO_INCREMENT=81718 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=81718 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `item_translations`
--
DROP TABLE IF EXISTS `item_translations`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `item_translations` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`item_id` int(11) DEFAULT NULL,
`locale` varchar(255) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`description` text,
`rarity` varchar(255) DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_item_translations_on_item_id` (`item_id`),
KEY `index_item_translations_on_locale` (`locale`),
KEY `index_item_translations_name` (`name`),
KEY `index_item_translations_on_item_id_and_locale` (`item_id`,`locale`)
) ENGINE=InnoDB AUTO_INCREMENT=215758 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
@ -53,4 +77,4 @@ CREATE TABLE `items` (
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2020-09-18 5:22:43 -- Dump completed on 2020-09-18 5:47:52

View file

@ -3,8 +3,10 @@ const mysql = require("mysql2");
let globalDb; let globalDb;
async function connectToDb({ async function connectToDb({
host = "impress.openneo.net",
user = process.env["IMPRESS_MYSQL_USER"], user = process.env["IMPRESS_MYSQL_USER"],
password = process.env["IMPRESS_MYSQL_PASSWORD"], password = process.env["IMPRESS_MYSQL_PASSWORD"],
database = "openneo_impress",
} = {}) { } = {}) {
if (globalDb) { if (globalDb) {
return globalDb; return globalDb;
@ -12,10 +14,10 @@ async function connectToDb({
globalDb = mysql globalDb = mysql
.createConnection({ .createConnection({
host: "impress.openneo.net", host,
user, user,
password, password,
database: "openneo_impress", database,
multipleStatements: true, multipleStatements: true,
}) })
// We upgrade to promises here, instead of using the mysql2/promise import, // We upgrade to promises here, instead of using the mysql2/promise import,

View file

@ -1,5 +1,5 @@
const gql = require("graphql-tag"); const gql = require("graphql-tag");
const { query, getDbCalls } = require("./setup.js"); const { query, getDbCalls, clearDbCalls, useTestDb } = require("./setup.js");
describe("Pet", () => { describe("Pet", () => {
it("looks up a pet", async () => { it("looks up a pet", async () => {
@ -50,4 +50,61 @@ describe("Pet", () => {
] ]
`); `);
}); });
it.skip("models new item data", async () => {
useTestDb();
const res = await query({
query: gql`
query {
petOnNeopetsDotCom(petName: "roopal27") {
items {
id
name
description
thumbnailUrl
rarityIndex
isNc
}
}
}
`,
});
expect(res).toHaveNoErrors();
expect(res.data).toMatchSnapshot();
expect(getDbCalls()).toMatchInlineSnapshot(`Array []`);
clearDbCalls();
const res2 = await query({
query: gql`
query {
items(
ids: [
"37229"
"37375"
"38911"
"38912"
"38913"
"43014"
"43397"
"48313"
]
) {
id
name
description
thumbnailUrl
rarityIndex
isNc
}
}
`,
});
expect(res2).toHaveNoErrors();
expect(res2.data).toMatchSnapshot();
expect(getDbCalls()).toMatchInlineSnapshot();
});
}); });

View file

@ -81,3 +81,76 @@ Object {
}, },
} }
`; `;
exports[`Pet models new item data 1`] = `
Object {
"petOnNeopetsDotCom": Object {
"items": Array [
Object {
"description": "What does this ball actually do?",
"id": "37229",
"isNc": false,
"name": "Magic Ball Table",
"rarityIndex": 101,
"thumbnailUrl": "http://images.neopets.com/items/gif_magicball_table.gif",
},
Object {
"description": "Dont forget to wish upon a star.",
"id": "37375",
"isNc": false,
"name": "Moon and Stars Background",
"rarityIndex": 75,
"thumbnailUrl": "http://images.neopets.com/items/bg_moonstars.gif",
},
Object {
"description": "Hide your face and hair so no one can recognise you.",
"id": "38911",
"isNc": false,
"name": "Zafara Agent Hood",
"rarityIndex": 92,
"thumbnailUrl": "http://images.neopets.com/items/clo_zafara_agent_hood.gif",
},
Object {
"description": "This robe is great for being stealthy.",
"id": "38912",
"isNc": false,
"name": "Zafara Agent Robe",
"rarityIndex": 90,
"thumbnailUrl": "http://images.neopets.com/items/clo_zafara_agent_robe.gif",
},
Object {
"description": "Dont leave any trace that you were there with these gloves.",
"id": "38913",
"isNc": false,
"name": "Zafara Agent Gloves",
"rarityIndex": 88,
"thumbnailUrl": "http://images.neopets.com/items/clo_zafara_agent_gloves.gif",
},
Object {
"description": "These leaves almost look magical with their gentle glow.",
"id": "43014",
"isNc": false,
"name": "Green Leaf String Lights",
"rarityIndex": 80,
"thumbnailUrl": "http://images.neopets.com/items/toy_stringlight_illleaf.gif",
},
Object {
"description": "This jewelled staff shines with a magical light.",
"id": "43397",
"isNc": true,
"name": "Jewelled Staff",
"rarityIndex": 500,
"thumbnailUrl": "http://images.neopets.com/items/mall_staff_jewelled.gif",
},
Object {
"description": "Even the announcers of the Altador Cup celebrate. This was given out by the Advent Calendar in Y11.",
"id": "48313",
"isNc": false,
"name": "Altador Cup Brooch",
"rarityIndex": 101,
"thumbnailUrl": "http://images.neopets.com/items/clo_altcuplogo_brooch.gif",
},
],
},
}
`;

View file

@ -1,3 +1,6 @@
const fs = require("fs");
const path = require("path");
const { ApolloServer } = require("apollo-server"); const { ApolloServer } = require("apollo-server");
const { createTestClient } = require("apollo-server-testing"); const { createTestClient } = require("apollo-server-testing");
const { AuthenticationClient } = require("auth0"); const { AuthenticationClient } = require("auth0");
@ -29,9 +32,40 @@ const { query } = createTestClient(
jest.mock("../db"); jest.mock("../db");
let dbExecuteFn; let dbExecuteFn;
let db; let db;
let dbEnvironment = "production";
const dbSetupScripts = [
fs
.readFileSync(
path.join(__dirname, "../../../scripts/setup-mysql-dev-constants.sql")
)
.toString(),
fs
.readFileSync(
path.join(__dirname, "../../../scripts/setup-mysql-dev-schema.sql")
)
.toString(),
];
beforeAll(() => { beforeAll(() => {
connectToDb.mockImplementation(async (...args) => { connectToDb.mockImplementation(async () => {
db = await actualConnectToDb(...args); let options;
if (dbEnvironment === "test") {
options = {
host: "localhost",
user: "impress_2020_test",
password: "impress_2020_test",
database: "impress_2020_test",
};
}
db = await actualConnectToDb(options);
if (dbEnvironment === "test") {
for (const script of dbSetupScripts) {
await db.query(script);
}
}
dbExecuteFn = jest.spyOn(db, "execute"); dbExecuteFn = jest.spyOn(db, "execute");
return db; return db;
}); });
@ -41,6 +75,7 @@ beforeEach(() => {
if (dbExecuteFn) { if (dbExecuteFn) {
dbExecuteFn.mockClear(); dbExecuteFn.mockClear();
} }
dbEnvironment = "production";
}); });
afterAll(() => { afterAll(() => {
if (db) { if (db) {
@ -48,6 +83,14 @@ afterAll(() => {
} }
}); });
const getDbCalls = () => (dbExecuteFn ? dbExecuteFn.mock.calls : []); const getDbCalls = () => (dbExecuteFn ? dbExecuteFn.mock.calls : []);
const clearDbCalls = () => dbExecuteFn?.mockClear();
function useTestDb() {
if (db) {
throw new Error(`can't call useTestDb() if db mock already exists`);
}
dbEnvironment = "test";
}
async function logInAsTestUser() { async function logInAsTestUser() {
const auth0 = new AuthenticationClient({ const auth0 = new AuthenticationClient({
@ -83,4 +126,10 @@ expect.extend({
}, },
}); });
module.exports = { query, getDbCalls, logInAsTestUser }; module.exports = {
query,
getDbCalls,
clearDbCalls,
useTestDb,
logInAsTestUser,
};