lux-framework
Version:
Build scalable, Node.js-powered REST APIs with almost no code.
310 lines (246 loc) • 8.05 kB
JavaScript
// @flow
import { expect } from 'chai';
import { it, describe, before, beforeEach, afterEach } from 'mocha';
import { get, set } from '../relationship';
import range from '../../../utils/range';
import { getTestApp } from '../../../../test/utils/get-test-app';
import type { Model } from '../index';
describe('module "database/relationship"', () => {
let Tag: Class<Model>;
let Post: Class<Model>;
let User: Class<Model>;
let Image: Class<Model>;
let Comment: Class<Model>;
let Categorization: Class<Model>;
before(async () => {
const { models } = await getTestApp();
// $FlowIgnore
Tag = models.get('tag');
// $FlowIgnore
Post = models.get('post');
// $FlowIgnore
User = models.get('user');
// $FlowIgnore
Image = models.get('image');
// $FlowIgnore
Comment = models.get('comment');
// $FlowIgnore
Categorization = models.get('categorization');
});
describe('#get()', () => {
const instances = new Set();
let subject;
let subjectId;
const setup = async () => {
subject = await Post.create({
title: '#get() test',
userId: 1
});
subject = subject.unwrap();
subjectId = subject.getPrimaryKey();
await Post.transaction(async trx => {
const [image, tags, comments] = await Promise.all([
Image.transacting(trx).create({
url: 'http://postlight.com',
postId: subjectId
}),
Promise.all(
Array.from(range(1, 5)).map(num => (
Tag.transacting(trx).create({
name: `New Tag ${num}`
})
))
),
Promise.all(
Array.from(range(1, 5)).map(num => (
Comment.transacting(trx).create({
message: `New Comment ${num}`,
userId: 2,
postId: subjectId
})
))
)
]);
const categorizations = await Promise.all(
tags.map(tag => (
Categorization.transacting(trx).create({
tagId: tag.getPrimaryKey(),
postId: subjectId
})
))
);
instances.add(image);
tags.forEach(tag => {
instances.add(tag);
});
comments.forEach(comment => {
instances.add(comment);
});
categorizations.forEach(categorization => {
instances.add(categorization);
});
});
};
const teardown = () => subject.transaction(async trx => {
await Promise.all([
subject.transacting(trx).destroy(),
...Array
.from(instances)
.map(record => record.transacting(trx).destroy())
]);
});
describe('has-one relationships', () => {
beforeEach(setup);
afterEach(teardown);
it('resolves with the correct value when present', async () => {
const result = await get(subject, 'image');
expect(result).to.be.an.instanceof(Image);
expect(result).to.have.property('postId', subjectId);
});
});
describe('belongs-to relationships', () => {
beforeEach(setup);
afterEach(teardown);
it('resolves with the correct value when present', async () => {
const result = await get(subject, 'user');
expect(result).to.be.an.instanceof(User);
expect(result).to.have.property('id', 1);
});
});
describe('one-to-many relationships', () => {
beforeEach(setup);
afterEach(teardown);
it('resolves with the correct value when present', async () => {
const result = await get(subject, 'comments');
expect(result).to.be.an('array').with.lengthOf(5);
if (Array.isArray(result)) {
result.forEach(comment => {
expect(comment).to.be.an.instanceof(Comment);
expect(comment).to.have.property('postId', subjectId);
});
}
});
});
describe('many-to-many relationships', () => {
beforeEach(setup);
afterEach(teardown);
it('resolves with the correct value when present', async () => {
const result = await get(subject, 'tags');
expect(result).to.be.an('array').with.lengthOf(5);
if (Array.isArray(result)) {
result.forEach(tag => {
expect(tag).to.be.an.instanceof(Tag);
});
const categorizations = await Promise.all(
result.map(tag => {
const tagId = tag.getPrimaryKey();
return Categorization.first().where({
tagId
});
})
);
expect(categorizations).to.be.an('array').with.lengthOf(5);
categorizations.forEach(categorization => {
expect(categorization).to.be.an.instanceof(Categorization);
expect(categorization).to.have.property('postId', subjectId);
});
}
});
});
});
describe('#set()', () => {
const instances = new Set();
let subject;
let subjectId;
const setup = async () => {
subject = await Post.create({
title: '#set() test'
});
subject = subject.unwrap();
subjectId = subject.getPrimaryKey();
};
const teardown = () => subject.transaction(async trx => {
await Promise.all([
subject.transacting(trx).destroy(),
...Array
.from(instances)
.map(record => record.transacting(trx).destroy())
]);
});
describe('has-one relationships', () => {
let image;
beforeEach(async () => {
await setup();
image = await Image.create({
url: 'http://postlight.com'
});
image = image.unwrap();
instances.add(image);
set(subject, 'image', image);
});
afterEach(teardown);
it('can add a record to the relationship', async () => {
expect(image).to.have.property('postId', subjectId);
expect(await Reflect.get(image, 'post')).be.an.instanceof(Post);
});
});
describe('belongs-to relationships', () => {
let user;
beforeEach(async () => {
await setup();
user = await User.create({
name: 'Test User',
email: 'test-user@postlight.com',
password: 'test12345678'
});
user = user.unwrap();
instances.add(user);
set(subject, 'user', user);
});
afterEach(teardown);
it('can add a record to the relationship', async () => {
expect(subject).to.have.property('userId', user.getPrimaryKey());
expect(await Reflect.get(subject, 'user')).to.be.an.instanceof(User);
});
it('can remove a record from the relationship', async () => {
set(subject, 'user', null);
expect(subject).to.have.property('userId', null);
expect(await Reflect.get(subject, 'user')).to.be.null;
});
});
describe('one-to-many relationships', () => {
let comments;
beforeEach(async () => {
await setup();
comments = await Comment.transaction(trx => (
Promise.all(
[1, 2, 3].map(num => (
Comment
.transacting(trx)
.create({
message: `Test Comment ${num}`
})
.then(record => record.unwrap())
))
)
));
comments.forEach(comment => {
instances.add(comment);
});
set(subject, 'comments', comments);
});
afterEach(teardown);
it('can add records to the relationship', () => {
comments.forEach(comment => {
expect(comment).to.have.property('postId', subjectId);
});
});
it('can remove records from the relationship', () => {
set(subject, 'comments', []);
comments.forEach(comment => {
expect(comment).to.have.property('postId', null);
});
});
});
});
});