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

test: add and use util to inject one metadata manager #893

Merged
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
3 changes: 3 additions & 0 deletions projects/ngx-meta/api-extractor/ngx-meta.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ export const _HEAD_ELEMENT_UPSERT_OR_REMOVE: InjectionToken<_HeadElementUpsertOr
// @internal (undocumented)
export type _HeadElementUpsertOrRemove = (selector: string, element: HTMLElement | null | undefined) => void;

// @internal (undocumented)
export const _injectMetadataManagers: () => ReadonlyArray<NgxMetaMetadataManager>;

// @internal
export const _isDefined: <T>(value: T | null | undefined) => value is T;

Expand Down
23 changes: 23 additions & 0 deletions projects/ngx-meta/src/__tests__/inject-one-metadata-manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Injects the only metadata manager found.
*
* Throws if no one is found or more than one is found.
*/
import {
_injectMetadataManagers,
NgxMetaMetadataManager,
} from '@davidlj95/ngx-meta/core'
import { TestBed } from '@angular/core/testing'

export const injectOneMetadataManager = <T>(): NgxMetaMetadataManager<T> => {
const managers = TestBed.runInInjectionContext(_injectMetadataManagers)
if (managers.length > 1) {
throw new Error(
`More than one metadata manager found (${managers.length}). Just one is expected`,
)
}
if (managers.length === 0) {
throw new Error(`No metadata manager found. One is expected`)
}
return managers[0]
}
1 change: 1 addition & 0 deletions projects/ngx-meta/src/core/src/managers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export {
MakeMetadataManagerProviderFromSetterFactoryOptions,
} from './make-metadata-manager-provider-from-setter-factory'
export {
_injectMetadataManagers,
NgxMetaMetadataManager,
MetadataSetter,
MetadataResolverOptions,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { InjectionToken, Provider } from '@angular/core'
import {
injectMetadataManagers,
_injectMetadataManagers,
NgxMetaMetadataManager,
} from './ngx-meta-metadata-manager'

Expand All @@ -13,7 +13,7 @@ export interface MetadataRegistry {
}

const metadataRegistryFactory: () => MetadataRegistry = () => {
const managers = injectMetadataManagers()
const managers = _injectMetadataManagers()
const managersById = new Map<string, NgxMetaMetadataManager>()
const register: MetadataRegistry['register'] = (manager) => {
if (managersById.has(manager.id)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ export abstract class NgxMetaMetadataManager<Value = unknown> {
abstract readonly set: MetadataSetter<Value>
}

export const injectMetadataManagers: () => ReadonlyArray<NgxMetaMetadataManager> =
/**
* @internal
*/
export const _injectMetadataManagers: () => ReadonlyArray<NgxMetaMetadataManager> =
() =>
// https://stackoverflow.com/q/74598049/3263250
(inject(NgxMetaMetadataManager, {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { TestBed } from '@angular/core/testing'
import { MockProviders } from 'ng-mocks'
import { MetadataSetter, NgxMetaMetaService } from '@davidlj95/ngx-meta/core'
import { MockProvider } from 'ng-mocks'
import {
NgxMetaMetadataManager,
NgxMetaMetaService,
} from '@davidlj95/ngx-meta/core'
import { enableAutoSpy } from '@/ngx-meta/test/enable-auto-spy'
import { OpenGraphImage } from './open-graph-image'
import { OpenGraph } from '../../types'
import { OPEN_GRAPH_IMAGE_SETTER_FACTORY } from './open-graph-image-metadata-provider'
import { injectOneMetadataManager } from '@/ngx-meta/test/inject-one-metadata-manager'
import { OPEN_GRAPH_IMAGE_METADATA_PROVIDER } from './open-graph-image-metadata-provider'

describe('Open Graph image metadata', () => {
describe('Open Graph image metadata manager', () => {
enableAutoSpy()
let sut: MetadataSetter<OpenGraph['image']>
let sut: NgxMetaMetadataManager<OpenGraph['image']>
let metaService: jasmine.SpyObj<NgxMetaMetaService>

beforeEach(() => {
Expand All @@ -29,7 +33,7 @@ describe('Open Graph image metadata', () => {

describe('when url is provided', () => {
it('should set all meta properties', () => {
sut(image)
sut.set(image)

const props = Object.keys(image).length
expect(metaService.set).toHaveBeenCalledTimes(props)
Expand Down Expand Up @@ -62,7 +66,7 @@ describe('Open Graph image metadata', () => {

describe('when no url is defined', () => {
it('should remove all meta properties', () => {
sut({ ...image, url: undefined })
sut.set({ ...image, url: undefined })

const props = Object.keys(image).length
expect(metaService.set).toHaveBeenCalledTimes(props)
Expand All @@ -73,9 +77,12 @@ describe('Open Graph image metadata', () => {
})
})

function makeSut(): MetadataSetter<OpenGraph['image']> {
function makeSut(): NgxMetaMetadataManager<OpenGraph['image']> {
TestBed.configureTestingModule({
providers: [MockProviders(NgxMetaMetaService)],
providers: [
MockProvider(NgxMetaMetaService),
OPEN_GRAPH_IMAGE_METADATA_PROVIDER,
],
})
return OPEN_GRAPH_IMAGE_SETTER_FACTORY(TestBed.inject(NgxMetaMetaService))
return injectOneMetadataManager()
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ import { TestBed } from '@angular/core/testing'
import {
_URL_RESOLVER,
_UrlResolver,
MetadataSetter,
NgxMetaMetadataManager,
NgxMetaMetaService,
} from '@davidlj95/ngx-meta/core'
import { OpenGraph } from '../../types'
import { OPEN_GRAPH_URL_SETTER_FACTORY } from './open-graph-url-metadata-provider'
import { OPEN_GRAPH_URL_METADATA_PROVIDER } from './open-graph-url-metadata-provider'
import { enableAutoSpy } from '@/ngx-meta/test/enable-auto-spy'
import { MockProvider } from 'ng-mocks'
import { injectOneMetadataManager } from '@/ngx-meta/test/inject-one-metadata-manager'

describe('Open Graph URL metadata', () => {
describe('Open Graph URL metadata manager', () => {
enableAutoSpy()
let urlResolver: jasmine.Spy<_UrlResolver>
let sut: MetadataSetter<OpenGraph['url']>
let sut: NgxMetaMetadataManager<OpenGraph['url']>
let metaService: jasmine.SpyObj<NgxMetaMetaService>
const dummyUrl = 'dummy-url'
const dummyResolvedUrl = 'https://example.com/dummy-resolved-url'
Expand All @@ -27,7 +28,7 @@ describe('Open Graph URL metadata', () => {
})

it('should use resolved URL as metadata value', () => {
sut(dummyUrl)
sut.set(dummyUrl)

expect(metaService.set).toHaveBeenCalledWith(
jasmine.anything(),
Expand All @@ -39,18 +40,16 @@ describe('Open Graph URL metadata', () => {

function makeSut(opts: {
urlResolver: _UrlResolver
}): MetadataSetter<OpenGraph['url']> {
}): NgxMetaMetadataManager<OpenGraph['url']> {
TestBed.configureTestingModule({
providers: [
MockProvider(NgxMetaMetaService),
{
provide: _URL_RESOLVER,
useValue: opts.urlResolver ?? jasmine.createSpy(),
},
OPEN_GRAPH_URL_METADATA_PROVIDER,
],
})
return OPEN_GRAPH_URL_SETTER_FACTORY(
TestBed.inject(NgxMetaMetaService),
TestBed.inject(_URL_RESOLVER),
)
return injectOneMetadataManager()
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import {
_HeadElementUpsertOrRemove,
_URL_RESOLVER,
_UrlResolver,
NgxMetaMetadataManager,
} from '@davidlj95/ngx-meta/core'
import { TestBed } from '@angular/core/testing'
import { STANDARD_CANONICAL_URL_SETTER_FACTORY } from './standard-canonical-url-metadata-provider'
import { DOCUMENT } from '@angular/common'
import { injectOneMetadataManager } from '@/ngx-meta/test/inject-one-metadata-manager'
import { Standard } from '../types'
import { STANDARD_CANONICAL_URL_METADATA_PROVIDER } from './standard-canonical-url-metadata-provider'

describe('Standard canonical URL metadata provider', () => {
describe('Standard canonical URL metadata manager', () => {
enableAutoSpy()

const LINK_REL_CANONICAL_SELECTOR = "link[rel='canonical']"
Expand All @@ -23,7 +25,7 @@ describe('Standard canonical URL metadata provider', () => {
jasmine.createSpy<_HeadElementUpsertOrRemove>()
const sut = makeSut({ headElementUpsertOrRemove })

sut(testCase)
sut.set(testCase)

expect(headElementUpsertOrRemove).toHaveBeenCalledWith(
LINK_REL_CANONICAL_SELECTOR,
Expand Down Expand Up @@ -51,7 +53,7 @@ describe('Standard canonical URL metadata provider', () => {
})
const sut = makeSut({ headElementUpsertOrRemove })

sut(dummyAbsoluteUrl)
sut.set(dummyAbsoluteUrl)

expect(receivedSelector).toEqual(LINK_REL_CANONICAL_SELECTOR)
expect(receivedElement?.tagName.toLowerCase()).toEqual('link')
Expand All @@ -72,7 +74,7 @@ describe('Standard canonical URL metadata provider', () => {

const sut = makeSut({ headElementUpsertOrRemove, urlResolver })

sut(dummyRelativeUrl)
sut.set(dummyRelativeUrl)

expect(receivedElement?.getAttribute('href')).toEqual(dummyAbsoluteUrl)
})
Expand All @@ -85,7 +87,7 @@ describe('Standard canonical URL metadata provider', () => {

const sut = makeSut({ urlResolver })

sut(dummyRelativeUrl)
sut.set(dummyRelativeUrl)

expect(console.warn).toHaveBeenCalledWith(
jasmine.stringContaining('should be absolute'),
Expand All @@ -99,7 +101,7 @@ const makeSut = (
headElementUpsertOrRemove?: _HeadElementUpsertOrRemove
urlResolver?: _UrlResolver
} = {},
) => {
): NgxMetaMetadataManager<Standard['canonicalUrl']> => {
TestBed.configureTestingModule({
providers: [
{
Expand All @@ -116,11 +118,8 @@ const makeSut = (
.createSpy<_UrlResolver>('URL Resolver')
.and.callFake((url) => url?.toString()),
},
STANDARD_CANONICAL_URL_METADATA_PROVIDER,
],
})
return STANDARD_CANONICAL_URL_SETTER_FACTORY(
TestBed.inject(_HEAD_ELEMENT_UPSERT_OR_REMOVE),
TestBed.inject(DOCUMENT),
TestBed.inject(_URL_RESOLVER),
)
return injectOneMetadataManager()
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { TestBed } from '@angular/core/testing'
import { MockProvider } from 'ng-mocks'
import { enableAutoSpy } from '@/ngx-meta/test/enable-auto-spy'
import { MetadataSetter, NgxMetaMetaService } from '@davidlj95/ngx-meta/core'
import {
NgxMetaMetadataManager,
NgxMetaMetaService,
} from '@davidlj95/ngx-meta/core'
import { VERSION } from '@angular/core'
import { Standard } from '../types'
import { STANDARD_GENERATOR_METADATA_SETTER_FACTORY } from './standard-generator-metadata-provider'
import { STANDARD_GENERATOR_METADATA_PROVIDER } from './standard-generator-metadata-provider'
import { injectOneMetadataManager } from '@/ngx-meta/test/inject-one-metadata-manager'

describe('Standard generator metadata', () => {
describe('Standard generator metadata manager', () => {
enableAutoSpy()
let sut: MetadataSetter<Standard['generator']>
let sut: NgxMetaMetadataManager<Standard['generator']>
let metaService: jasmine.SpyObj<NgxMetaMetaService>

beforeEach(() => {
Expand All @@ -18,34 +22,42 @@ describe('Standard generator metadata', () => {
) as jasmine.SpyObj<NgxMetaMetaService>
})

it('when not provided should call meta service with nothing value', () => {
sut(undefined)
describe('when not provided', () => {
const TEST_CASES = [null, undefined]
TEST_CASES.forEach((testCase) => {
describe(`like when ${testCase}`, () => {
it(`should call meta service with ${testCase}`, () => {
sut.set(undefined)

expect(metaService.set).toHaveBeenCalledOnceWith(
jasmine.anything(),
undefined,
)
expect(metaService.set).toHaveBeenCalledOnceWith(
jasmine.anything(),
undefined,
)
})
})
})
})
it('when null should call meta service with null value', () => {
sut(null)

expect(metaService.set).toHaveBeenCalledOnceWith(jasmine.anything(), null)
})
it('when true should call meta service with Angular version as value', () => {
sut(true)
describe('when true', () => {
const value: Standard['generator'] = true

it('should call meta service with Angular version as value', () => {
sut.set(value)

expect(metaService.set).toHaveBeenCalledOnceWith(
jasmine.anything(),
`Angular v${VERSION.full}`,
)
expect(metaService.set).toHaveBeenCalledOnceWith(
jasmine.anything(),
`Angular v${VERSION.full}`,
)
})
})
})

function makeSut(): MetadataSetter<Standard['generator']> {
function makeSut(): NgxMetaMetadataManager<Standard['generator']> {
TestBed.configureTestingModule({
providers: [MockProvider(NgxMetaMetaService)],
providers: [
MockProvider(NgxMetaMetaService),
STANDARD_GENERATOR_METADATA_PROVIDER,
],
})
return STANDARD_GENERATOR_METADATA_SETTER_FACTORY(
TestBed.inject(NgxMetaMetaService),
)
return injectOneMetadataManager()
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { TestBed } from '@angular/core/testing'
import { MockProvider } from 'ng-mocks'
import { enableAutoSpy } from '@/ngx-meta/test/enable-auto-spy'
import { MetadataSetter, NgxMetaMetaService } from '@davidlj95/ngx-meta/core'
import {
NgxMetaMetadataManager,
NgxMetaMetaService,
} from '@davidlj95/ngx-meta/core'
import { Standard } from '../types'
import { STANDARD_KEYWORDS_METADATA_SETTER_FACTORY } from './standard-keywords-metadata-provider'
import { STANDARD_KEYWORDS_METADATA_PROVIDER } from './standard-keywords-metadata-provider'
import { injectOneMetadataManager } from '@/ngx-meta/test/inject-one-metadata-manager'

describe('Standard keywords metadata', () => {
describe('Standard keywords metadata manager', () => {
enableAutoSpy()
let sut: MetadataSetter<Standard['keywords']>
let sut: NgxMetaMetadataManager<Standard['keywords']>
let metaService: jasmine.SpyObj<NgxMetaMetaService>

beforeEach(() => {
Expand All @@ -22,7 +26,7 @@ describe('Standard keywords metadata', () => {
const secondKeyword = 'second'
const thirdKeyword = 'third'

sut([firstKeyword, secondKeyword, thirdKeyword])
sut.set([firstKeyword, secondKeyword, thirdKeyword])

expect(metaService.set).toHaveBeenCalledOnceWith(
jasmine.anything(),
Expand All @@ -31,11 +35,12 @@ describe('Standard keywords metadata', () => {
})
})

function makeSut(): MetadataSetter<Standard['keywords']> {
function makeSut(): NgxMetaMetadataManager<Standard['keywords']> {
TestBed.configureTestingModule({
providers: [MockProvider(NgxMetaMetaService)],
providers: [
MockProvider(NgxMetaMetaService),
STANDARD_KEYWORDS_METADATA_PROVIDER,
],
})
return STANDARD_KEYWORDS_METADATA_SETTER_FACTORY(
TestBed.inject(NgxMetaMetaService),
)
return injectOneMetadataManager()
}
Loading