Skip to content

Commit

Permalink
test(repository-tests): adding acceptance tests for hasManyThrough re…
Browse files Browse the repository at this point in the history
…lation
  • Loading branch information
Agnes Lin committed Jun 17, 2020
1 parent a6cf16e commit 2577f13
Show file tree
Hide file tree
Showing 11 changed files with 391 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
// Copyright IBM Corp. 2020. 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 {expect, toJSON} from '@loopback/testlab';
import {
CrudFeatures,
CrudRepositoryCtor,
CrudTestContext,
DataSourceOptions,
} from '../../..';
import {
deleteAllModelsInDefaultDataSource,
MixedIdType,
withCrudCtx,
} from '../../../helpers.repository-tests';
import {
CartItem,
CartItemRepository,
Customer,
CustomerCartItemLink,
CustomerCartItemLinkRepository,
CustomerRepository,
} from '../fixtures/models';
import {givenBoundCrudRepositories} from '../helpers';

export function hasManyThroughRelationAcceptance(
dataSourceOptions: DataSourceOptions,
repositoryClass: CrudRepositoryCtor,
features: CrudFeatures,
) {
describe('HasManyThrough relation (acceptance)', () => {
before(deleteAllModelsInDefaultDataSource);
let customerRepo: CustomerRepository;
let cartItemRepo: CartItemRepository;
let customerCartItemLinkRepo: CustomerCartItemLinkRepository;
let existingCustomerId: MixedIdType;

before(
withCrudCtx(async function setupRepository(ctx: CrudTestContext) {
({
customerRepo,
cartItemRepo,
customerCartItemLinkRepo,
} = givenBoundCrudRepositories(
ctx.dataSource,
repositoryClass,
features,
));
await ctx.dataSource.automigrate([
Customer.name,
CartItem.name,
CustomerCartItemLink.name,
]);
}),
);

beforeEach(async () => {
await customerRepo.deleteAll();
await cartItemRepo.deleteAll();
await customerCartItemLinkRepo.deleteAll();
});

beforeEach(async () => {
existingCustomerId = (await givenPersistedCustomerInstance()).id;
});

it('can create an instance of the related model alone with a through model', async () => {
const item = await customerRepo
.cartItems(existingCustomerId)
.create(
{description: 'an item'},
{throughData: {description: 'a through model'}},
);

expect(toJSON(item)).containDeep(
toJSON({
id: item.id,
description: 'an item',
}),
);

const persistedItem = await cartItemRepo.findById(item.id);
expect(toJSON(persistedItem)).to.deepEqual(toJSON(item));
const persistedLink = await customerCartItemLinkRepo.find();
expect(toJSON(persistedLink[0])).to.containDeep(
toJSON({
customerId: existingCustomerId,
cartItemId: item.id,
description: 'a through model',
}),
);
});

it('can find instances of the related model', async () => {
const item = await customerRepo
.cartItems(existingCustomerId)
.create(
{description: 'an item'},
{throughData: {description: 'a through model'}},
);
const notMyItem = await cartItemRepo.create({
description: "someone else's item",
});
const result = await customerRepo.cartItems(existingCustomerId).find();
expect(toJSON(result)).to.containDeep(toJSON([item]));
expect(toJSON(result[0])).to.not.containEql(toJSON(notMyItem));
});

it('can patch an instance', async () => {
const item1 = await customerRepo
.cartItems(existingCustomerId)
.create({description: 'group 1'});
const item2 = await customerRepo
.cartItems(existingCustomerId)
.create({description: 'group 1'});
const count = await customerRepo
.cartItems(existingCustomerId)
.patch({description: 'group 2'}, {id: item2.id});

expect(count.count).to.equal(1);
const result = await customerRepo.cartItems(existingCustomerId).find();
expect(toJSON(result)).to.containDeep(
toJSON([
{id: item1.id, description: 'group 1'},
{id: item2.id, description: 'group 2'},
]),
);
});

it('throws error when query tries to change the target id', async () => {
// a diff id for CartItem instance
const anotherId = (await givenPersistedCustomerInstance()).id;
await customerRepo
.cartItems(existingCustomerId)
.create({description: 'group 1'});

await expect(
customerRepo.cartItems(existingCustomerId).patch({id: anotherId}),
).to.be.rejectedWith(/Property "id" cannot be changed!/);
});

it('can delete many instances and their through models', async () => {
await customerRepo
.cartItems(existingCustomerId)
.create({description: 'group 1'});
await customerRepo
.cartItems(existingCustomerId)
.create({description: 'group 1'});

let links = await customerCartItemLinkRepo.find();
let cartItems = await cartItemRepo.find();
expect(links).have.length(2);
expect(cartItems).have.length(2);

await customerRepo.cartItems(existingCustomerId).delete();
links = await customerCartItemLinkRepo.find();
cartItems = await cartItemRepo.find();
expect(links).have.length(0);
expect(cartItems).have.length(0);
});

it('can delete corresponding through models when the target gets deleted', async () => {
const item = await customerRepo
.cartItems(existingCustomerId)
.create({description: 'group 1'});
const anotherId = (await givenPersistedCustomerInstance()).id;
// another through model that links to the same item
await customerCartItemLinkRepo.create({
customerId: anotherId,
cartItemId: item.id,
});

let links = await customerCartItemLinkRepo.find();
let cartItems = await cartItemRepo.find();
expect(links).have.length(2);
expect(cartItems).have.length(1);

await customerRepo.cartItems(existingCustomerId).delete();
links = await customerCartItemLinkRepo.find();
cartItems = await cartItemRepo.find();
expect(links).have.length(0);
expect(cartItems).have.length(0);
});

async function givenPersistedCustomerInstance() {
return customerRepo.create({name: 'a customer'});
}
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright IBM Corp. 2020. 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 {
Entity,
EntityCrudRepository,
model,
property,
} from '@loopback/repository';
import {MixedIdType} from '../../../../helpers.repository-tests';

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

@property({
type: 'string',
})
description: string;
}

export interface CartItemRelations {}

export type CartItemWithRelations = CartItem & CartItemRelations;

export interface CartItemRepository
extends EntityCrudRepository<CartItem, typeof CartItem.prototype.id> {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright IBM Corp. 2020. 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 {
Entity,
EntityCrudRepository,
model,
property,
} from '@loopback/repository';
import {MixedIdType} from '../../../../helpers.repository-tests';

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

@property()
customerId: MixedIdType;

@property()
cartItemId: MixedIdType;

@property({
type: 'string',
})
description?: string;
}

export interface CustomerCartItemLinkRelations {}

export type CustomerCartItemLinkWithRelations = CustomerCartItemLink &
CustomerCartItemLinkRelations;

export interface CustomerCartItemLinkRepository
extends EntityCrudRepository<
CustomerCartItemLink,
typeof CustomerCartItemLink.prototype.id
> {}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
EntityCrudRepository,
hasMany,
HasManyRepositoryFactory,
HasManyThroughRepositoryFactory,
hasOne,
HasOneRepositoryFactory,
model,
Expand All @@ -17,6 +18,8 @@ import {
import {BelongsToAccessor} from '@loopback/repository/src';
import {MixedIdType} from '../../../../helpers.repository-tests';
import {Address, AddressWithRelations} from './address.model';
import {CartItem, CartItemWithRelations} from './cart-item.model';
import {CustomerCartItemLink} from './customer-cart-item-link.model';
import {Order, OrderWithRelations} from './order.model';

@model()
Expand Down Expand Up @@ -44,13 +47,17 @@ export class Customer extends Entity {

@belongsTo(() => Customer)
parentId?: MixedIdType;

@hasMany(() => CartItem, {through: {model: () => CustomerCartItemLink}})
cartItems: CartItem[];
}

export interface CustomerRelations {
address?: AddressWithRelations;
orders?: OrderWithRelations[];
customers?: CustomerWithRelations[];
parentCustomer?: CustomerWithRelations;
cartItems?: CartItemWithRelations[];
}

export type CustomerWithRelations = Customer & CustomerRelations;
Expand All @@ -62,4 +69,10 @@ export interface CustomerRepository
orders: HasManyRepositoryFactory<Order, MixedIdType>;
customers: HasManyRepositoryFactory<Customer, MixedIdType>;
parent: BelongsToAccessor<Customer, MixedIdType>;
cartItems: HasManyThroughRepositoryFactory<
CartItem,
MixedIdType,
CustomerCartItemLink,
MixedIdType
>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
// License text available at https://opensource.org/licenses/MIT

export * from './address.model';
export * from './cart-item.model';
export * from './customer-cart-item-link.model';
export * from './customer.model';
export * from './order.model';
export * from './shipment.model';
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright IBM Corp. 2020. 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 {juggler} from '@loopback/repository';
import {CrudRepositoryCtor} from '../../../..';
import {CartItem, CartItemRelations} from '../models';

// create the CartItemRepo by calling this func so that it can be extended from CrudRepositoryCtor
export function createCartItemRepo(repoClass: CrudRepositoryCtor) {
return class CartItemRepository extends repoClass<
CartItem,
typeof CartItem.prototype.id,
CartItemRelations
> {
constructor(db: juggler.DataSource) {
super(CartItem, db);
}
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright IBM Corp. 2020. 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 {juggler} from '@loopback/repository';
import {CrudRepositoryCtor} from '../../../..';
import {CustomerCartItemLink, CustomerCartItemLinkRelations} from '../models';
// create the CustomerCartItemLinkRepo by calling this func so that it can be extended from CrudRepositoryCtor
export function createCustomerCartItemLinkRepo(repoClass: CrudRepositoryCtor) {
return class CustomerCartItemLinkRepository extends repoClass<
CustomerCartItemLink,
typeof CustomerCartItemLink.prototype.id,
CustomerCartItemLinkRelations
> {
constructor(db: juggler.DataSource) {
super(CustomerCartItemLink, db);
}
};
}
Loading

0 comments on commit 2577f13

Please sign in to comment.