test coverage for user creation
This commit is contained in:
parent
09af351e06
commit
3b57af74ca
|
@ -0,0 +1,86 @@
|
||||||
|
const { map, reduce, filter, isEmpty, flatten, each, union } = require("lodash/fp");
|
||||||
|
const { compileCode } = require("../common/compileCode");
|
||||||
|
const { validateFieldParse, validateTypeConstraints } = require("../schema/types");
|
||||||
|
import {
|
||||||
|
validateFieldParse,
|
||||||
|
validateTypeConstraints,
|
||||||
|
} from "../schema/types/index.js"
|
||||||
|
import { $, isNonEmptyString } from "../common/index.mjs"
|
||||||
|
|
||||||
|
const fieldParseError = (fieldName, value) => ({
|
||||||
|
fields: [fieldName],
|
||||||
|
message: `Could not parse field ${fieldName}:${value}`,
|
||||||
|
})
|
||||||
|
|
||||||
|
const validateAllFieldParse = (record, model) =>
|
||||||
|
$(model.fields, [
|
||||||
|
map(f => ({ name: f.name, parseResult: validateFieldParse(f, record) })),
|
||||||
|
reduce((errors, f) => {
|
||||||
|
if (f.parseResult.success) return errors
|
||||||
|
errors.push(fieldParseError(f.name, f.parseResult.value))
|
||||||
|
return errors
|
||||||
|
}, []),
|
||||||
|
])
|
||||||
|
|
||||||
|
const validateAllTypeConstraints = (record, model) => {
|
||||||
|
const errors = []
|
||||||
|
for (const field of model.fields) {
|
||||||
|
$(validateTypeConstraints(field, record), [
|
||||||
|
filter(isNonEmptyString),
|
||||||
|
map(m => ({ message: m, fields: [field.name] })),
|
||||||
|
each(e => errors.push(e)),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
return errors
|
||||||
|
}
|
||||||
|
|
||||||
|
const runRecordValidationRules = (record, model) => {
|
||||||
|
const runValidationRule = rule => {
|
||||||
|
const isValid = compileCode(rule.expressionWhenValid)
|
||||||
|
const expressionContext = { record }
|
||||||
|
return isValid(expressionContext)
|
||||||
|
? { valid: true }
|
||||||
|
: {
|
||||||
|
valid: false,
|
||||||
|
fields: rule.invalidFields,
|
||||||
|
message: rule.messageWhenInvalid,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $(model.validationRules, [
|
||||||
|
map(runValidationRule),
|
||||||
|
flatten,
|
||||||
|
filter(r => r.valid === false),
|
||||||
|
map(r => ({ fields: r.fields, message: r.message })),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
export const validateRecord = (schema, record) => {
|
||||||
|
const model = schema.findModel(record._modelId)
|
||||||
|
const fieldParseFails = validateAllFieldParse(record, model)
|
||||||
|
|
||||||
|
// non parsing would cause further issues - exit here
|
||||||
|
if (!isEmpty(fieldParseFails)) {
|
||||||
|
return { isValid: false, errors: fieldParseFails }
|
||||||
|
}
|
||||||
|
|
||||||
|
const recordValidationRuleFails = runRecordValidationRules(record, model)
|
||||||
|
const typeContraintFails = validateAllTypeConstraints(record, model)
|
||||||
|
|
||||||
|
if (
|
||||||
|
isEmpty(fieldParseFails) &&
|
||||||
|
isEmpty(recordValidationRuleFails) &&
|
||||||
|
isEmpty(typeContraintFails)
|
||||||
|
) {
|
||||||
|
return { isValid: true, errors: [] }
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
isValid: false,
|
||||||
|
errors: union(
|
||||||
|
fieldParseFails,
|
||||||
|
typeContraintFails,
|
||||||
|
recordValidationRuleFails
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import { testSchema } from "./testSchema.mjs"
|
import { testSchema } from "./testSchema.mjs"
|
||||||
import { validateRecord } from "../src/records/validateRecord.mjs"
|
import { validateRecord } from "../src/records/validateRecord.js"
|
||||||
import { getNewRecord } from "../src/records/getNewRecord.mjs"
|
import { getNewRecord } from "../src/records/getNewRecord.mjs"
|
||||||
|
|
||||||
describe("validateRecord", () => {
|
describe("validateRecord", () => {
|
||||||
|
|
|
@ -12,10 +12,20 @@ exports.fetch = async function(ctx) {
|
||||||
|
|
||||||
exports.create = async function(ctx) {
|
exports.create = async function(ctx) {
|
||||||
const database = couchdb.db.use(ctx.params.databaseId);
|
const database = couchdb.db.use(ctx.params.databaseId);
|
||||||
ctx.body = await database.insert(ctx.request.body);
|
const response = await database.insert(ctx.request.body);
|
||||||
|
ctx.body = {
|
||||||
|
...response,
|
||||||
|
message: `User created successfully.`,
|
||||||
|
status: 200
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.destroy = async function(ctx) {
|
exports.destroy = async function(ctx) {
|
||||||
const database = couchdb.db.use(ctx.params.databaseId);
|
const database = couchdb.db.use(ctx.params.databaseId);
|
||||||
ctx.body = await database.destroy(ctx.params.userId)
|
const response = await database.destroy(ctx.params.userId)
|
||||||
|
ctx.body = {
|
||||||
|
...response,
|
||||||
|
message: `User deleted.`,
|
||||||
|
status: 200
|
||||||
|
}
|
||||||
};
|
};
|
|
@ -31,3 +31,8 @@ exports.createInstanceDatabase = async instanceId => {
|
||||||
}
|
}
|
||||||
}, '_design/database');
|
}, '_design/database');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.insertDocument = async (databaseId, document) => {
|
||||||
|
const { id, ...documentFields } = document;
|
||||||
|
await couchdb.db.use(databaseId).insert(documentFields, id);
|
||||||
|
}
|
|
@ -1,29 +1,68 @@
|
||||||
const couchdb = require("../../../../db");
|
const couchdb = require("../../../../db");
|
||||||
const supertest = require("supertest");
|
const supertest = require("supertest");
|
||||||
const app = require("../../../../app");
|
const app = require("../../../../app");
|
||||||
const { createInstanceDatabase } = require("./couchTestUtils");
|
const { createInstanceDatabase, insertDocument, destroyDatabase } = require("./couchTestUtils");
|
||||||
|
|
||||||
|
|
||||||
const TEST_INSTANCE_ID = "testing-123";
|
const TEST_INSTANCE_ID = "testing-123";
|
||||||
|
const TEST_USER = {
|
||||||
|
name: "Dave"
|
||||||
|
}
|
||||||
|
|
||||||
describe("/users", () => {
|
describe("/users", () => {
|
||||||
let request;
|
let request;
|
||||||
|
let server;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const server = await app({
|
server = await app({
|
||||||
config: {
|
config: {
|
||||||
port: 3000
|
port: 3000
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
request = supertest(server);
|
request = supertest(server);
|
||||||
createInstanceDatabase(TEST_INSTANCE_ID);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
app.close();
|
server.close();
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("fetch", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await createInstanceDatabase(TEST_INSTANCE_ID);
|
||||||
|
await insertDocument(TEST_INSTANCE_ID, {
|
||||||
|
id: "cool-user-id",
|
||||||
|
type: "user",
|
||||||
|
name: "Dave"
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await destroyDatabase(TEST_INSTANCE_ID);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns a list of users from an instance db", done => {
|
||||||
|
request
|
||||||
|
.get(`/api/${TEST_INSTANCE_ID}/users`)
|
||||||
|
.set("Accept", "application/json")
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(200)
|
||||||
|
.end(async (err, res) => {
|
||||||
|
const createdUser = res.body[0].doc;
|
||||||
|
expect(createdUser.name).toEqual(TEST_USER.name);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
describe("create", () => {
|
describe("create", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await createInstanceDatabase(TEST_INSTANCE_ID);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await destroyDatabase(TEST_INSTANCE_ID);
|
||||||
|
});
|
||||||
|
|
||||||
it("returns a success message when a user is successfully created", done => {
|
it("returns a success message when a user is successfully created", done => {
|
||||||
request
|
request
|
||||||
.post(`/api/${TEST_INSTANCE_ID}/users`)
|
.post(`/api/${TEST_INSTANCE_ID}/users`)
|
||||||
|
@ -32,7 +71,7 @@ describe("/users", () => {
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.end(async (err, res) => {
|
.end(async (err, res) => {
|
||||||
expect(res.body.message).toEqual("Instance Database testing-123 successfully provisioned.");
|
expect(res.body.message).toEqual("User created successfully.");
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue