|
5 | 5 |
|
6 | 6 | import {expect} from '@loopback/testlab';
|
7 | 7 | import {Context, inject, Setter, Getter} from '../..';
|
| 8 | +import {Provider} from '../../src/provider'; |
| 9 | +import {Injection} from '../../src/inject'; |
| 10 | +import {ResolutionSession} from '../../src/resolution-session'; |
8 | 11 |
|
9 | 12 | const INFO_CONTROLLER = 'controllers.info';
|
10 | 13 |
|
11 | 14 | describe('Context bindings - Injecting dependencies of classes', () => {
|
12 | 15 | let ctx: Context;
|
13 |
| - before('given a context', createContext); |
| 16 | + beforeEach('given a context', createContext); |
14 | 17 |
|
15 | 18 | it('injects constructor args', async () => {
|
16 | 19 | ctx.bind('application.name').to('CodeHub');
|
@@ -177,6 +180,129 @@ describe('Context bindings - Injecting dependencies of classes', () => {
|
177 | 180 | expect(resolved.config).to.equal('test-config');
|
178 | 181 | });
|
179 | 182 |
|
| 183 | + it('injects values by tag', () => { |
| 184 | + class Store { |
| 185 | + constructor(@inject.tag('store:location') public locations: string[]) {} |
| 186 | + } |
| 187 | + |
| 188 | + ctx.bind('store').toClass(Store); |
| 189 | + ctx |
| 190 | + .bind('store.locations.sf') |
| 191 | + .to('San Francisco') |
| 192 | + .tag('store:location'); |
| 193 | + ctx |
| 194 | + .bind('store.locations.sj') |
| 195 | + .to('San Jose') |
| 196 | + .tag('store:location'); |
| 197 | + const store: Store = ctx.getSync('store'); |
| 198 | + expect(store.locations).to.eql(['San Francisco', 'San Jose']); |
| 199 | + }); |
| 200 | + |
| 201 | + it('injects values by tag regex', () => { |
| 202 | + class Store { |
| 203 | + constructor( |
| 204 | + @inject.tag(/.+:location:sj/) |
| 205 | + public locations: string[], |
| 206 | + ) {} |
| 207 | + } |
| 208 | + |
| 209 | + ctx.bind('store').toClass(Store); |
| 210 | + ctx |
| 211 | + .bind('store.locations.sf') |
| 212 | + .to('San Francisco') |
| 213 | + .tag('store:location:sf'); |
| 214 | + ctx |
| 215 | + .bind('store.locations.sj') |
| 216 | + .to('San Jose') |
| 217 | + .tag('store:location:sj'); |
| 218 | + const store: Store = ctx.getSync('store'); |
| 219 | + expect(store.locations).to.eql(['San Jose']); |
| 220 | + }); |
| 221 | + |
| 222 | + it('injects empty values by tag if not found', () => { |
| 223 | + class Store { |
| 224 | + constructor(@inject.tag('store:location') public locations: string[]) {} |
| 225 | + } |
| 226 | + |
| 227 | + ctx.bind('store').toClass(Store); |
| 228 | + const store: Store = ctx.getSync('store'); |
| 229 | + expect(store.locations).to.eql([]); |
| 230 | + }); |
| 231 | + |
| 232 | + it('injects values by tag asynchronously', async () => { |
| 233 | + class Store { |
| 234 | + constructor(@inject.tag('store:location') public locations: string[]) {} |
| 235 | + } |
| 236 | + |
| 237 | + ctx.bind('store').toClass(Store); |
| 238 | + ctx |
| 239 | + .bind('store.locations.sf') |
| 240 | + .to('San Francisco') |
| 241 | + .tag('store:location'); |
| 242 | + ctx |
| 243 | + .bind('store.locations.sj') |
| 244 | + .toDynamicValue(async () => 'San Jose') |
| 245 | + .tag('store:location'); |
| 246 | + const store: Store = await ctx.get('store'); |
| 247 | + expect(store.locations).to.eql(['San Francisco', 'San Jose']); |
| 248 | + }); |
| 249 | + |
| 250 | + it('injects values by tag asynchronously', async () => { |
| 251 | + class Store { |
| 252 | + constructor(@inject.tag('store:location') public locations: string[]) {} |
| 253 | + } |
| 254 | + |
| 255 | + let resolutionPath; |
| 256 | + class LocationProvider implements Provider<string> { |
| 257 | + @inject( |
| 258 | + 'location', |
| 259 | + {}, |
| 260 | + // Set up a custom resolve() to access information from the session |
| 261 | + (c: Context, injection: Injection, session: ResolutionSession) => { |
| 262 | + resolutionPath = session.getResolutionPath(); |
| 263 | + return 'San Jose'; |
| 264 | + }, |
| 265 | + ) |
| 266 | + location: string; |
| 267 | + value() { |
| 268 | + return this.location; |
| 269 | + } |
| 270 | + } |
| 271 | + |
| 272 | + ctx.bind('store').toClass(Store); |
| 273 | + ctx |
| 274 | + .bind('store.locations.sf') |
| 275 | + .to('San Francisco') |
| 276 | + .tag('store:location'); |
| 277 | + ctx |
| 278 | + .bind('store.locations.sj') |
| 279 | + .toProvider(LocationProvider) |
| 280 | + .tag('store:location'); |
| 281 | + const store: Store = await ctx.get('store'); |
| 282 | + expect(store.locations).to.eql(['San Francisco', 'San Jose']); |
| 283 | + expect(resolutionPath).to.eql( |
| 284 | + 'store --> @Store.constructor[0] --> store.locations.sj --> ' + |
| 285 | + '@LocationProvider.prototype.location', |
| 286 | + ); |
| 287 | + }); |
| 288 | + |
| 289 | + it('reports error when @inject.tag rejects a promise', async () => { |
| 290 | + class Store { |
| 291 | + constructor(@inject.tag('store:location') public locations: string[]) {} |
| 292 | + } |
| 293 | + |
| 294 | + ctx.bind('store').toClass(Store); |
| 295 | + ctx |
| 296 | + .bind('store.locations.sf') |
| 297 | + .to('San Francisco') |
| 298 | + .tag('store:location'); |
| 299 | + ctx |
| 300 | + .bind('store.locations.sj') |
| 301 | + .toDynamicValue(() => Promise.reject(new Error('Bad'))) |
| 302 | + .tag('store:location'); |
| 303 | + await expect(ctx.get('store')).to.be.rejectedWith('Bad'); |
| 304 | + }); |
| 305 | + |
180 | 306 | function createContext() {
|
181 | 307 | ctx = new Context();
|
182 | 308 | }
|
|
0 commit comments