/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {IMAGE_LOADER, ImageLoader, PRECONNECT_CHECK_BLOCKLIST} from '@angular/common/src/directives/ng_optimized_image';
import {provideCloudflareLoader} from '@angular/common/src/directives/ng_optimized_image/image_loaders/cloudflare_loader';
import {provideCloudinaryLoader} from '@angular/common/src/directives/ng_optimized_image/image_loaders/cloudinary_loader';
import {provideImageKitLoader} from '@angular/common/src/directives/ng_optimized_image/image_loaders/imagekit_loader';
import {provideImgixLoader} from '@angular/common/src/directives/ng_optimized_image/image_loaders/imgix_loader';
import {isValidPath} from '@angular/common/src/directives/ng_optimized_image/util';
import {createEnvironmentInjector, EnvironmentInjector, ValueProvider} from '@angular/core';
import {TestBed} from '@angular/core/testing';
describe('Built-in image directive loaders', () => {
describe('Imgix loader', () => {
function createImgixLoader(path: string): ImageLoader {
const injector = createEnvironmentInjector(
[provideImgixLoader(path)], TestBed.inject(EnvironmentInjector));
return injector.get(IMAGE_LOADER);
}
it('should construct an image loader with the given path', () => {
const path = 'https://somesite.imgix.net';
const loader = createImgixLoader(path);
const config = {src: 'img.png'};
expect(loader(config)).toBe(`${path}/img.png?auto=format`);
});
it('should handle a trailing forward slash on the path', () => {
const path = 'https://somesite.imgix.net';
const loader = createImgixLoader(`${path}/`);
const config = {src: 'img.png'};
expect(loader(config)).toBe(`${path}/img.png?auto=format`);
});
it('should handle a leading forward slash on the image src', () => {
const path = 'https://somesite.imgix.net';
const loader = createImgixLoader(path);
const config = {src: '/img.png'};
expect(loader(config)).toBe(`${path}/img.png?auto=format`);
});
it('should construct an image loader with the given path', () => {
const path = 'https://somesite.imgix.net';
const loader = createImgixLoader(path);
const config = {src: 'img.png', width: 100};
expect(loader(config)).toBe(`${path}/img.png?auto=format&w=100`);
});
it('should throw if an absolute URL is provided as a loader input', () => {
const path = 'https://somesite.imgix.net';
const src = 'https://angular.io/img.png';
const loader = createImgixLoader(path);
expect(() => loader({src}))
.toThrowError(
`NG02959: Image loader has detected an absolute URL used for one ` +
`of the \`rawSrc\` attributes on an \`
\` tag: ${src}. ` +
`The absolute URLs are not supported by this image loader. Please update ` +
`the \`rawSrc\` attribute of that \`
\` tag to use a path relative to the ` +
`base URL configured for this loader (\`${path}\`).`);
});
});
describe('Cloudinary loader', () => {
function createCloudinaryLoader(path: string): ImageLoader {
const injector = createEnvironmentInjector(
[provideCloudinaryLoader(path)], TestBed.inject(EnvironmentInjector));
return injector.get(IMAGE_LOADER);
}
it('should construct an image loader with the given path', () => {
const path = 'https://res.cloudinary.com/mysite';
const loader = createCloudinaryLoader(path);
expect(loader({src: 'img.png'})).toBe(`${path}/image/upload/f_auto,q_auto/img.png`);
expect(loader({
src: 'marketing/img-2.png'
})).toBe(`${path}/image/upload/f_auto,q_auto/marketing/img-2.png`);
});
describe('input validation', () => {
it('should throw if an absolute URL is provided as a loader input', () => {
const path = 'https://res.cloudinary.com/mysite';
const src = 'https://angular.io/img.png';
const loader = createCloudinaryLoader(path);
expect(() => loader({src}))
.toThrowError(
`NG02959: Image loader has detected an absolute URL used for one ` +
`of the \`rawSrc\` attributes on an \`
\` tag: ${src}. ` +
`The absolute URLs are not supported by this image loader. Please update ` +
`the \`rawSrc\` attribute of that \`
\` tag to use a path relative to the ` +
`base URL configured for this loader (\`${path}\`).`);
});
it('should throw if the path is invalid', () => {
expect(() => provideCloudinaryLoader('my-cloudinary-account'))
.toThrowError(
`NG02959: Image loader has detected an invalid path. ` +
`Expecting a path matching one of the following formats: ` +
`https://res.cloudinary.com/mysite or https://mysite.cloudinary.com ` +
`or https://subdomain.mysite.com - but got: \`my-cloudinary-account\``);
});
it('should handle a trailing forward slash on the path', () => {
const path = 'https://res.cloudinary.com/mysite';
const loader = createCloudinaryLoader(`${path}/`);
expect(loader({src: 'img.png'})).toBe(`${path}/image/upload/f_auto,q_auto/img.png`);
});
it('should handle a leading forward slash on the image src', () => {
const path = 'https://res.cloudinary.com/mysite';
const loader = createCloudinaryLoader(path);
expect(loader({src: '/img.png'})).toBe(`${path}/image/upload/f_auto,q_auto/img.png`);
});
});
});
describe('ImageKit loader', () => {
function createImageKitLoader(path: string): ImageLoader {
const injector = createEnvironmentInjector(
[provideImageKitLoader(path)], TestBed.inject(EnvironmentInjector));
return injector.get(IMAGE_LOADER);
}
it('should construct an image loader with the given path', () => {
const path = 'https://ik.imageengine.io/imagetest';
const loader = createImageKitLoader(path);
expect(loader({src: 'img.png'})).toBe(`${path}/tr:q-auto/img.png`);
expect(loader({src: 'marketing/img-2.png'})).toBe(`${path}/tr:q-auto/marketing/img-2.png`);
});
describe('input validation', () => {
it('should throw if an absolute URL is provided as a loader input', () => {
const path = 'https://ik.imageengine.io/imagetest';
const src = 'https://angular.io/img.png';
const loader = createImageKitLoader(path);
expect(() => loader({src}))
.toThrowError(
`NG02959: Image loader has detected an absolute URL used for one ` +
`of the \`rawSrc\` attributes on an \`
\` tag: ${src}. ` +
`The absolute URLs are not supported by this image loader. Please update ` +
`the \`rawSrc\` attribute of that \`
\` tag to use a path relative to the ` +
`base URL configured for this loader (\`${path}\`).`);
});
it('should throw if the path is invalid', () => {
expect(() => provideImageKitLoader('my-imagekit-account'))
.toThrowError(
`NG02959: Image loader has detected an invalid path. ` +
`Expecting a path matching one of the following formats: ` +
`https://ik.imagekit.io/mysite or https://subdomain.mysite.com - ` +
`but got: \`my-imagekit-account\``);
});
it('should handle a trailing forward slash on the path', () => {
const path = 'https://ik.imageengine.io/imagetest';
const loader = createImageKitLoader(`${path}/`);
expect(loader({src: 'img.png'})).toBe(`${path}/tr:q-auto/img.png`);
});
it('should handle a leading forward slash on the image src', () => {
const path = 'https://ik.imageengine.io/imagetest';
const loader = createImageKitLoader(path);
expect(loader({src: '/img.png'})).toBe(`${path}/tr:q-auto/img.png`);
});
});
});
describe('Cloudflare loader', () => {
function createCloudflareLoader(path: string): ImageLoader {
const injector = createEnvironmentInjector(
[provideCloudflareLoader(path)], TestBed.inject(EnvironmentInjector));
return injector.get(IMAGE_LOADER);
}
it('should construct an image loader with the given path', () => {
const loader = createCloudflareLoader('https://mysite.com');
let config = {src: 'img.png'};
expect(loader(config)).toBe('https://mysite.com/cdn-cgi/image/format=auto/img.png');
});
it('should construct an image loader with the given path', () => {
const loader = createCloudflareLoader('https://mysite.com');
const config = {src: 'img.png', width: 100};
expect(loader(config)).toBe('https://mysite.com/cdn-cgi/image/format=auto,width=100/img.png');
});
it('should throw if an absolute URL is provided as a loader input', () => {
const path = 'https://mysite.com';
const src = 'https://angular.io/img.png';
const loader = createCloudflareLoader(path);
expect(() => loader({src}))
.toThrowError(
`NG02959: Image loader has detected an absolute URL used for one ` +
`of the \`rawSrc\` attributes on an \`
\` tag: ${src}. ` +
`The absolute URLs are not supported by this image loader. Please update ` +
`the \`rawSrc\` attribute of that \`
\` tag to use a path relative to the ` +
`base URL configured for this loader (\`${path}\`).`);
});
});
describe('ensurePreconnect option', () => {
const path = 'https://some.host/base';
[provideImgixLoader,
provideCloudinaryLoader,
provideImageKitLoader,
provideCloudflareLoader,
].forEach(provideImageLoader => {
it(`${provideImageLoader.name} should _not_ block-list path by default`, () => {
const providers = provideImageLoader(path);
expect(providers.length).toBe(1);
const valueProvider = providers[0] as ValueProvider;
expect(valueProvider.provide).not.toBe(PRECONNECT_CHECK_BLOCKLIST);
});
it(`${provideImageLoader.name} should _not_ block-list path when ensurePreconnect is true`,
() => {
const providers = provideImageLoader(path, {ensurePreconnect: true});
expect(providers.length).toBe(1);
const valueProvider = providers[0] as ValueProvider;
expect(valueProvider.provide).not.toBe(PRECONNECT_CHECK_BLOCKLIST);
});
it('`${provideImageLoader.name} should block-list path when ensurePreconnect is false',
() => {
const providers = provideImageLoader(path, {ensurePreconnect: false});
expect(providers.length).toBe(2);
const valueProvider = providers[1] as ValueProvider;
expect(valueProvider.multi).toBeTrue();
expect(valueProvider.useValue).toEqual([path]);
expect(valueProvider.provide).toBe(PRECONNECT_CHECK_BLOCKLIST);
});
});
});
describe('loader utils', () => {
it('should identify valid paths', () => {
expect(isValidPath('https://cdn.imageprovider.com/image-test')).toBe(true);
expect(isValidPath('https://cdn.imageprovider.com')).toBe(true);
expect(isValidPath('https://imageprovider.com')).toBe(true);
});
it('should reject empty paths', () => {
expect(isValidPath('')).toBe(false);
});
it('should reject path if it is not a URL', () => {
expect(isValidPath('myaccount')).toBe(false);
});
it('should reject path if it does not include a protocol', () => {
expect(isValidPath('myaccount.imageprovider.com')).toBe(false);
});
it('should reject path if is malformed', () => {
expect(isValidPath('somepa\th.imageprovider.com? few')).toBe(false);
});
});
});