test(common): optimize image loader tests of the NgOptimizedImage directive (#47082)

This commit updates the image loader tests to avoid creating the TestBed environment, since it's not really needed for the tests. Instead, the loader functions are invoked directly and the output is verified.

PR Close #47082
This commit is contained in:
Andrew Kushnir
2022-06-07 15:15:45 -07:00
committed by Pawel Kozlowski
parent 98f20436ec
commit 3774d84cfb
2 changed files with 83 additions and 152 deletions
@@ -696,19 +696,18 @@ describe('Image directive', () => {
it('should set `src` to match `rawSrc` if image loader is not provided', () => {
setupTestingModule();
const template = '<img rawSrc="https://somesite.imgix.net/img.png" width="100" height="50">';
const template = `<img rawSrc="${IMG_BASE_URL}/img.png" width="100" height="50">`;
const fixture = createTestComponent(template);
fixture.detectChanges();
const nativeElement = fixture.nativeElement as HTMLElement;
const img = nativeElement.querySelector('img')!;
expect(img.src).toBe('https://somesite.imgix.net/img.png');
expect(img.src).toBe(`${IMG_BASE_URL}/img.png`);
});
it('should set `src` using the image loader provided via the `IMAGE_LOADER` token to compose src URL',
() => {
const imageLoader = (config: ImageLoaderConfig) =>
`https://somesite.imgix.net/${config.src}`;
const imageLoader = (config: ImageLoaderConfig) => `${IMG_BASE_URL}/${config.src}`;
setupTestingModule({imageLoader});
const template = `
@@ -720,14 +719,14 @@ describe('Image directive', () => {
const nativeElement = fixture.nativeElement as HTMLElement;
const imgs = nativeElement.querySelectorAll('img')!;
expect(imgs[0].src.trim()).toBe('https://somesite.imgix.net/img.png');
expect(imgs[1].src.trim()).toBe('https://somesite.imgix.net/img-2.png');
expect(imgs[0].src.trim()).toBe(`${IMG_BASE_URL}/img.png`);
expect(imgs[1].src.trim()).toBe(`${IMG_BASE_URL}/img-2.png`);
});
it('should set `src` to an image URL that does not include a default width parameter', () => {
const imageLoader = (config: ImageLoaderConfig) => {
const widthStr = config.width ? `?w=${config.width}` : ``;
return `https://somesite.imgix.net/${config.src}${widthStr}`;
return `${IMG_BASE_URL}/${config.src}${widthStr}`;
};
setupTestingModule({imageLoader});
@@ -737,7 +736,7 @@ describe('Image directive', () => {
const nativeElement = fixture.nativeElement as HTMLElement;
const img = nativeElement.querySelector('img')!;
expect(img.src).toBe('https://somesite.imgix.net/img.png');
expect(img.src).toBe(`${IMG_BASE_URL}/img.png`);
});
describe('`rawSrcset` values', () => {
@@ -746,7 +745,7 @@ describe('Image directive', () => {
beforeEach(() => {
imageLoader = (config: ImageLoaderConfig) => {
const width = config.width ? `?w=${config.width}` : ``;
return `https://somesite.imgix.net/${config.src}${width}`;
return `${IMG_BASE_URL}/${config.src}${width}`;
};
});
@@ -761,7 +760,7 @@ describe('Image directive', () => {
const nativeElement = fixture.nativeElement as HTMLElement;
const img = nativeElement.querySelector('img')!;
expect(img.src).toBe('https://somesite.imgix.net/img-100.png');
expect(img.src).toBe(`${IMG_BASE_URL}/img-100.png`);
expect(img.srcset).toBe('');
});
@@ -776,10 +775,9 @@ describe('Image directive', () => {
const nativeElement = fixture.nativeElement as HTMLElement;
const img = nativeElement.querySelector('img')!;
expect(img.src).toBe('https://somesite.imgix.net/img.png');
expect(img.src).toBe(`${IMG_BASE_URL}/img.png`);
expect(img.srcset)
.toBe(
'https://somesite.imgix.net/img.png?w=100 100w, https://somesite.imgix.net/img.png?w=200 200w');
.toBe(`${IMG_BASE_URL}/img.png?w=100 100w, ${IMG_BASE_URL}/img.png?w=200 200w`);
});
it('should set the `srcset` using the `rawSrcset` value with density descriptors', () => {
@@ -793,10 +791,9 @@ describe('Image directive', () => {
const nativeElement = fixture.nativeElement as HTMLElement;
const img = nativeElement.querySelector('img')!;
expect(img.src).toBe('https://somesite.imgix.net/img.png');
expect(img.src).toBe(`${IMG_BASE_URL}/img.png`);
expect(img.srcset)
.toBe(
'https://somesite.imgix.net/img.png?w=100 1x, https://somesite.imgix.net/img.png?w=200 2x');
.toBe(`${IMG_BASE_URL}/img.png?w=100 1x, ${IMG_BASE_URL}/img.png?w=200 2x`);
});
it('should set the `srcset` if `rawSrcset` has only one src defined', () => {
@@ -810,8 +807,8 @@ describe('Image directive', () => {
const nativeElement = fixture.nativeElement as HTMLElement;
const img = nativeElement.querySelector('img')!;
expect(img.src.trim()).toBe('https://somesite.imgix.net/img.png');
expect(img.srcset.trim()).toBe('https://somesite.imgix.net/img.png?w=100 100w');
expect(img.src.trim()).toBe(`${IMG_BASE_URL}/img.png`);
expect(img.srcset.trim()).toBe(`${IMG_BASE_URL}/img.png?w=100 100w`);
});
it('should set the `srcset` if `rawSrcSet` has extra spaces', () => {
@@ -825,10 +822,9 @@ describe('Image directive', () => {
const nativeElement = fixture.nativeElement as HTMLElement;
const img = nativeElement.querySelector('img')!;
expect(img.src).toBe('https://somesite.imgix.net/img.png');
expect(img.src).toBe(`${IMG_BASE_URL}/img.png`);
expect(img.srcset)
.toBe(
'https://somesite.imgix.net/img.png?w=100 100w, https://somesite.imgix.net/img.png?w=200 200w');
.toBe(`${IMG_BASE_URL}/img.png?w=100 100w, ${IMG_BASE_URL}/img.png?w=200 200w`);
});
it('should set the `srcset` if `rawSrcSet` has a trailing comma', () => {
@@ -842,10 +838,9 @@ describe('Image directive', () => {
const nativeElement = fixture.nativeElement as HTMLElement;
const img = nativeElement.querySelector('img')!;
expect(img.src).toBe('https://somesite.imgix.net/img.png');
expect(img.src).toBe(`${IMG_BASE_URL}/img.png`);
expect(img.srcset)
.toBe(
'https://somesite.imgix.net/img.png?w=100 1x, https://somesite.imgix.net/img.png?w=200 2x');
.toBe(`${IMG_BASE_URL}/img.png?w=100 1x, ${IMG_BASE_URL}/img.png?w=200 2x`);
});
it('should set the `srcset` if `rawSrcSet` has 3+ srcs', () => {
@@ -859,10 +854,12 @@ describe('Image directive', () => {
const nativeElement = fixture.nativeElement as HTMLElement;
const img = nativeElement.querySelector('img')!;
expect(img.src).toBe('https://somesite.imgix.net/img.png');
expect(img.src).toBe(`${IMG_BASE_URL}/img.png`);
expect(img.srcset)
.toBe(
'https://somesite.imgix.net/img.png?w=100 100w, https://somesite.imgix.net/img.png?w=200 200w, https://somesite.imgix.net/img.png?w=300 300w');
`${IMG_BASE_URL}/img.png?w=100 100w, ` +
`${IMG_BASE_URL}/img.png?w=200 200w, ` +
`${IMG_BASE_URL}/img.png?w=300 300w`);
});
it('should set the `srcset` if `rawSrcSet` has decimal density descriptors', () => {
@@ -876,10 +873,12 @@ describe('Image directive', () => {
const nativeElement = fixture.nativeElement as HTMLElement;
const img = nativeElement.querySelector('img')!;
expect(img.src).toBe('https://somesite.imgix.net/img.png');
expect(img.src).toBe(`${IMG_BASE_URL}/img.png`);
expect(img.srcset)
.toBe(
'https://somesite.imgix.net/img.png?w=100 1x, https://somesite.imgix.net/img.png?w=250 2.5x, https://somesite.imgix.net/img.png?w=300 3x');
`${IMG_BASE_URL}/img.png?w=100 1x, ` +
`${IMG_BASE_URL}/img.png?w=250 2.5x, ` +
`${IMG_BASE_URL}/img.png?w=300 3x`);
});
});
});
@@ -887,6 +886,13 @@ describe('Image directive', () => {
// Helpers
// Base URL that can be used in tests to construct absolute URLs.
const IMG_BASE_URL = {
// Use `toString` here to delay referencing the `window` until the tests
// execution starts, otherwise the `window` might not be defined in Node env.
toString: () => window.location.origin
};
const ANGULAR_LOGO_BASE64 =
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==';
@@ -6,59 +6,70 @@
* found in the LICENSE file at https://angular.io/license
*/
import {CommonModule} from '@angular/common';
import {IMAGE_LOADER, ImageLoader, PRECONNECT_CHECK_BLOCKLIST} from '@angular/common/src/directives/ng_optimized_image';
import {provideImgixLoader} from '@angular/common/src/directives/ng_optimized_image/image_loaders/imgix_loader';
import {NgOptimizedImageModule} from '@angular/common/src/directives/ng_optimized_image/ng_optimized_image';
import {PRECONNECT_CHECK_BLOCKLIST} from '@angular/common/src/directives/ng_optimized_image/preconnect_link_checker';
import {RuntimeErrorCode} from '@angular/common/src/errors';
import {Component, ValueProvider} from '@angular/core';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {expect} from '@angular/platform-browser/testing/src/matchers';
import {createEnvironmentInjector, ValueProvider} from '@angular/core';
describe('Built-in image directive loaders', () => {
describe('Imgix loader', () => {
function createImgixLoader(path: string): ImageLoader {
const injector = createEnvironmentInjector([provideImgixLoader(path)]);
return injector.get(IMAGE_LOADER);
}
function invalidPathError(path: string): string {
return `NG0${RuntimeErrorCode.INVALID_INPUT}: ImgixLoader has detected ` +
`an invalid path: expecting a path like https://somepath.imgix.net/` +
`but got: \`${path}\``;
}
describe('invalid paths', () => {
it('should throw if path is empty', () => {
expect(() => {
setupTestingModule([provideImgixLoader('')]);
})
.toThrowError(
`NG0${RuntimeErrorCode.INVALID_INPUT}: ImgixLoader has detected an invalid path: ` +
`expecting a path like https://somepath.imgix.net/` +
`but got: \`\``);
it('should throw when a path is empty', () => {
const path = '';
expect(() => provideImgixLoader(path)).toThrowError(invalidPathError(path));
});
it('should throw if not a path', () => {
expect(() => {
setupTestingModule([provideImgixLoader('wellhellothere')]);
})
.toThrowError(
`NG0${RuntimeErrorCode.INVALID_INPUT}: ImgixLoader has detected an invalid path: ` +
`expecting a path like https://somepath.imgix.net/` +
`but got: \`wellhellothere\``);
it('should throw when a path is not a URL', () => {
const path = 'wellhellothere';
expect(() => provideImgixLoader(path)).toThrowError(invalidPathError(path));
});
it('should throw if path is missing a scheme', () => {
expect(() => {
setupTestingModule([provideImgixLoader('somepath.imgix.net')]);
})
.toThrowError(
`NG0${RuntimeErrorCode.INVALID_INPUT}: ImgixLoader has detected an invalid path: ` +
`expecting a path like https://somepath.imgix.net/` +
`but got: \`somepath.imgix.net\``);
it('should throw when a path is missing a scheme', () => {
const path = 'somepath.imgix.net';
expect(() => provideImgixLoader(path)).toThrowError(invalidPathError(path));
});
it('should throw if path is malformed', () => {
expect(() => {
setupTestingModule([provideImgixLoader('somepa\th.imgix.net? few')]);
})
.toThrowError(
`NG0${RuntimeErrorCode.INVALID_INPUT}: ImgixLoader has detected an invalid path: ` +
`expecting a path like https://somepath.imgix.net/` +
`but got: \`somepa\th.imgix.net? few\``);
it('should throw when a path is malformed', () => {
const path = 'somepa\th.imgix.net? few';
expect(() => provideImgixLoader(path)).toThrowError(invalidPathError(path));
});
});
it('should construct an image loader with the given path', () => {
const loader = createImgixLoader('https://somesite.imgix.net');
const config = {src: 'img.png'};
expect(loader(config)).toBe('https://somesite.imgix.net/img.png?auto=format');
});
it('should handle a trailing forward slash on the path', () => {
const loader = createImgixLoader('https://somesite.imgix.net/');
const config = {src: 'img.png'};
expect(loader(config)).toBe('https://somesite.imgix.net/img.png?auto=format');
});
it('should handle a leading forward slash on the src', () => {
const loader = createImgixLoader('https://somesite.imgix.net');
const config = {src: '/img.png'};
expect(loader(config)).toBe('https://somesite.imgix.net/img.png?auto=format');
});
it('should construct an image loader with the given path', () => {
const loader = createImgixLoader('https://somesite.imgix.net');
const config = {src: 'img.png', width: 100};
expect(loader(config)).toBe('https://somesite.imgix.net/img.png?auto=format&w=100');
});
describe('options', () => {
it('should configure PRECONNECT_CHECK_BLOCKLIST token by default', () => {
const providers = provideImgixLoader('https://somesite.imgix.net');
@@ -89,91 +100,5 @@ describe('Built-in image directive loaders', () => {
expect(providers.length).toBe(1);
});
});
it('should construct an image loader with the given path', () => {
setupTestingModule([provideImgixLoader('https://somesite.imgix.net')]);
const template = `
<img rawSrc="img.png" width="150" height="50">
<img rawSrc="img-2.png" width="150" height="50">
`;
const fixture = createTestComponent(template);
fixture.detectChanges();
const nativeElement = fixture.nativeElement as HTMLElement;
const imgs = nativeElement.querySelectorAll('img')!;
expect(imgs[0].src).toBe('https://somesite.imgix.net/img.png?auto=format');
expect(imgs[1].src).toBe('https://somesite.imgix.net/img-2.png?auto=format');
});
it('should handle a trailing forward slash on the path', () => {
setupTestingModule([provideImgixLoader('https://somesite.imgix.net/')]);
const template = `
<img rawSrc="img.png" width="150" height="50">
`;
const fixture = createTestComponent(template);
fixture.detectChanges();
const nativeElement = fixture.nativeElement as HTMLElement;
const img = nativeElement.querySelector('img')!;
expect(img.src).toBe('https://somesite.imgix.net/img.png?auto=format');
});
it('should handle a leading forward slash on the src', () => {
setupTestingModule([provideImgixLoader('https://somesite.imgix.net/')]);
const template = `
<img rawSrc="/img.png" width="150" height="50">
`;
const fixture = createTestComponent(template);
fixture.detectChanges();
const nativeElement = fixture.nativeElement as HTMLElement;
const img = nativeElement.querySelector('img')!;
expect(img.src).toBe('https://somesite.imgix.net/img.png?auto=format');
});
it('should be compatible with rawSrcset', () => {
setupTestingModule([provideImgixLoader('https://somesite.imgix.net')]);
const template = `
<img rawSrc="img.png" rawSrcset="100w, 200w" width="100" height="50">
`;
const fixture = createTestComponent(template);
fixture.detectChanges();
const nativeElement = fixture.nativeElement as HTMLElement;
const img = nativeElement.querySelector('img')!;
expect(img.src).toBe('https://somesite.imgix.net/img.png?auto=format');
expect(img.srcset)
.toBe(
'https://somesite.imgix.net/img.png?auto=format&w=100 100w, https://somesite.imgix.net/img.png?auto=format&w=200 200w');
});
});
});
// Helpers
@Component({
selector: 'test-cmp',
template: '',
})
class TestComponent {
}
function setupTestingModule(providers: any[]) {
TestBed.configureTestingModule({
declarations: [TestComponent],
// Note: the `NgOptimizedImage` directive is experimental and is not a part of the
// `CommonModule` yet, so it's imported separately.
imports: [CommonModule, NgOptimizedImageModule],
providers,
});
}
function createTestComponent(template: string): ComponentFixture<TestComponent> {
return TestBed.overrideComponent(TestComponent, {set: {template: template}})
.createComponent(TestComponent);
}