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

refactor(repository-tests): move relation tests to repository-tests package #3538

Merged
merged 1 commit into from
Sep 3, 2019
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
12 changes: 12 additions & 0 deletions packages/repository-tests/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion packages/repository-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@
"@loopback/build": "^1.7.1",
"@loopback/repository": "^1.12.0",
"@types/debug": "^4.1.5",
"@types/node": "^10.14.17"
"@types/node": "^10.14.17",
"@types/lodash": "^4.14.138",
"lodash": "^4.17.15"
},
"dependencies": {
"@loopback/testlab": "^1.7.4",
"@loopback/context":"1.21.4",
"@types/debug": "^4.1.5",
"debug": "^4.1.1"
},
Expand Down
25 changes: 24 additions & 1 deletion packages/repository-tests/src/crud-test-suite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,38 @@ export function crudRepositoryTestSuite(
}),
);

let testFiles = [];

const testRoot = path.resolve(__dirname, 'crud');
let testFiles = fs.readdirSync(testRoot);
testFiles = fs.readdirSync(testRoot);
testFiles = testFiles.filter(function(it) {
return (
!!require.extensions[path.extname(it).toLowerCase()] &&
/\.suite\.[^.]+$/.test(it)
);
});

// relations folder tests
const folders = ['acceptance'];

for (const folder of folders) {
const relationsTestRoot = path.resolve(
__dirname,
`crud/relations/${folder}`,
);
let folderTestFiles = fs.readdirSync(relationsTestRoot);
folderTestFiles = folderTestFiles.filter(function(it) {
return (
!!require.extensions[path.extname(it).toLowerCase()] &&
/\.acceptance\.[^.]+$/.test(it)
);
});
folderTestFiles.forEach(file => {
file = `relations/${folder}/` + file;
testFiles.push(file);
});
}

for (const ix in testFiles) {
const name = testFiles[ix];
const fullPath = path.resolve(testRoot, name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// License text available at https://opensource.org/licenses/MIT

import {Entity, model, property} from '@loopback/repository';
import {EntityCrudRepository} from '@loopback/repository/src';
import {EntityCrudRepository} from '@loopback/repository';
import {expect, skipIf, toJSON} from '@loopback/testlab';
import {Suite} from 'mocha';
import {
Expand Down
107 changes: 107 additions & 0 deletions packages/repository-tests/src/crud/nested-model-properties.suite.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright IBM Corp. 2019. All Rights Reserved.
// Node module: @loopback/repository-tests
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {
DefaultCrudRepository,
Entity,
EntityCrudRepository,
juggler,
model,
property,
} from '@loopback/repository';
import {expect, toJSON} from '@loopback/testlab';
import {
deleteAllModelsInDefaultDataSource,
withCrudCtx,
MixedIdType,
} from '../helpers.repository-tests';
import {
CrudFeatures,
CrudRepositoryCtor,
CrudTestContext,
DataSourceOptions,
} from '../types.repository-tests';

export function nestedModelsPropertiesSuite(
dataSourceOptions: DataSourceOptions,
repositoryClass: CrudRepositoryCtor,
features: CrudFeatures,
) {
describe('Nested models properties', () => {
let db: juggler.DataSource;
let userRepo: EntityCrudRepository<User, typeof User.prototype.id>;

before(deleteAllModelsInDefaultDataSource);

before(
withCrudCtx(async function setupRepository(ctx: CrudTestContext) {
db = ctx.dataSource;
userRepo = new DefaultCrudRepository<User, typeof User.prototype.id>(
User,
db,
);
const models = [User];
await db.automigrate(models.map(m => m.name));
}),
);
beforeEach(async function resetDatabase() {
await userRepo.deleteAll();
});

it('allows models to allow a singel nested model property', async () => {
const user = {
name: 'foo',
roles: [],
address: {street: 'backstreet'},
};
const created = await userRepo.create(user);

const stored = await userRepo.findById(created.id);
expect(toJSON(stored)).to.containDeep(toJSON(user));
});

it('allows models to allow multiple nested model properties in an array', async () => {
const user = {
name: 'foo',
roles: [{name: 'admin'}, {name: 'user'}],
address: {street: 'backstreet'},
agnes512 marked this conversation as resolved.
Show resolved Hide resolved
};
const created = await userRepo.create(user);

const stored = await userRepo.findById(created.id);
expect(toJSON(stored)).to.containDeep(toJSON(user));
});

@model()
class Role extends Entity {
@property()
name: string;
}

@model()
class Address extends Entity {
@property()
street: string;
}

@model()
class User extends Entity {
@property({
id: true,
generated: true,
})
id: MixedIdType;

@property({type: 'string'})
name: string;

@property.array(Role)
roles: Role[];

@property()
address: Address;
}
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Copyright IBM Corp. 2019. All Rights Reserved.
// Node module: @loopback/repository-tests
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {
BelongsToAccessor,
BelongsToDefinition,
createBelongsToAccessor,
EntityNotFoundError,
Getter,
} from '@loopback/repository';
import {expect, toJSON} from '@loopback/testlab';
import {
deleteAllModelsInDefaultDataSource,
withCrudCtx,
} from '../../../helpers.repository-tests';
import {
CrudFeatures,
CrudRepositoryCtor,
CrudTestContext,
DataSourceOptions,
} from '../../../types.repository-tests';
import {
Customer,
CustomerRepository,
Order,
OrderRepository,
Shipment,
ShipmentRepository,
} from '../fixtures/models';
import {givenBoundCrudRepositories} from '../helpers';

export function belongsToRelationAcceptance(
dataSourceOptions: DataSourceOptions,
repositoryClass: CrudRepositoryCtor,
features: CrudFeatures,
) {
describe('BelongsTo relation (acceptance)', () => {
before(deleteAllModelsInDefaultDataSource);

let findCustomerOfOrder: BelongsToAccessor<
Customer,
typeof Order.prototype.id
>;
let customerRepo: CustomerRepository;
let orderRepo: OrderRepository;
let shipmentRepo: ShipmentRepository;

before(
withCrudCtx(async function setupRepository(ctx: CrudTestContext) {
({customerRepo, orderRepo, shipmentRepo} = givenBoundCrudRepositories(
ctx.dataSource,
repositoryClass,
));
const models = [Customer, Order, Shipment];
await ctx.dataSource.automigrate(models.map(m => m.name));
}),
);
before(givenAccessor);
beforeEach(async () => {
await orderRepo.deleteAll();
});

it('can find customer of order', async () => {
const customer = await customerRepo.create({
name: 'Order McForder',
});
const order = await orderRepo.create({
customerId: customer.id,
description: 'Order from Order McForder, the hoarder of Mordor',
});

const result = await orderRepo.customer(order.id);
// adding parentId to customer so MySQL doesn't complain about null vs
// undefined
expect(toJSON(result)).to.deepEqual(
toJSON({...customer, parentId: features.emptyValue}),
agnes512 marked this conversation as resolved.
Show resolved Hide resolved
);
});

it('can find shipment of order with a custom foreign key name', async () => {
const shipment = await shipmentRepo.create({
name: 'Tuesday morning shipment',
});
const order = await orderRepo.create({
// eslint-disable-next-line @typescript-eslint/camelcase
shipment_id: shipment.id,
description: 'Order that is shipped Tuesday morning',
});
const result = await orderRepo.shipment(order.id);
expect(result).to.deepEqual(shipment);
});

it('throws EntityNotFound error when the related model does not exist', async () => {
const order = await orderRepo.create({
customerId: 999, // does not exist
description: 'Order of a fictional customer',
});

await expect(findCustomerOfOrder(order.id)).to.be.rejectedWith(
EntityNotFoundError,
);
});
// helpers
function givenAccessor() {
findCustomerOfOrder = createBelongsToAccessor(
Order.definition.relations.customer as BelongsToDefinition,
Getter.fromValue(customerRepo),
orderRepo,
);
}
});
}
Loading