-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: introduce meta element APIs v2 (#883)
- Loading branch information
Showing
11 changed files
with
463 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export { NgxMetaElementsService } from './ngx-meta-elements.service' | ||
export { NgxMetaElementNameAttribute } from './ngx-meta-element-name-attribute' | ||
export { NgxMetaElementAttributes } from './ngx-meta-element-attributes' | ||
export { withNameAttribute } from './with-name-attribute' | ||
export { withPropertyAttribute } from './with-property-attribute' | ||
export { withContentAttribute } from './with-content-attribute' |
26 changes: 26 additions & 0 deletions
26
projects/ngx-meta/src/core/src/meta-elements/v2/ngx-meta-element-attributes.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/** | ||
* Models a `<meta>` element HTML's attributes as a key / value JSON object. | ||
* | ||
* Almost equivalent to Angular's {@link https://angular.dev/api/platform-browser/MetaDefinition/ | MetaDefinition} | ||
* | ||
* Only difference is `http-equiv` property. In an Angular's | ||
* {@link https://angular.dev/api/platform-browser/MetaDefinition/ | MetaDefinition}, `httpEquiv` would also be | ||
* accepted. This way there's no need to quote the key property. | ||
* But without `httpEquiv` there's no need to map attribute names. So one bit of code less. | ||
* | ||
* @alpha | ||
*/ | ||
export type NgxMetaElementAttributes = Partial<{ | ||
charset: string | ||
content: string | ||
'http-equiv': string | ||
id: string | ||
itemprop: string | ||
name: string | ||
property: string | ||
scheme: string | ||
url: string | ||
media: string | ||
}> & { | ||
[key: string]: string | ||
} |
6 changes: 6 additions & 0 deletions
6
projects/ngx-meta/src/core/src/meta-elements/v2/ngx-meta-element-name-attribute.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/** | ||
* See {@link NgxMetaElementsService.set} | ||
* | ||
* @alpha | ||
*/ | ||
export type NgxMetaElementNameAttribute = readonly [name: string, value: string] |
172 changes: 172 additions & 0 deletions
172
projects/ngx-meta/src/core/src/meta-elements/v2/ngx-meta-elements.service.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
import { TestBed } from '@angular/core/testing' | ||
import { NgxMetaElementsService } from './ngx-meta-elements.service' | ||
import { withNameAttribute } from './with-name-attribute' | ||
import { withContentAttribute } from './with-content-attribute' | ||
import { Meta, MetaDefinition } from '@angular/platform-browser' | ||
|
||
describe('Meta element service', () => { | ||
const dummyMetaNameAttribute = withNameAttribute('dummy') | ||
const dummyMetaNameAttributeKeyValue = { name: 'dummy' } | ||
const dummyMetaContentAttribute = withContentAttribute('dummy') | ||
const dummyMetaAttributes = { | ||
...dummyMetaNameAttributeKeyValue, | ||
content: 'dummy', | ||
} | ||
|
||
const anotherDummyMetaContentAttribute = withContentAttribute('another-dummy') | ||
const anotherDummyMetaAttributes = { | ||
...dummyMetaNameAttributeKeyValue, | ||
content: 'another-dummy', | ||
} | ||
|
||
const yetAnotherDummyMetaContentAttribute = | ||
withContentAttribute('yet-another-dummy') | ||
const yetAnotherDummyMetaAttributes = { | ||
...dummyMetaNameAttributeKeyValue, | ||
content: 'yet-another-dummy', | ||
} | ||
|
||
const getDummyMetaElements = () => | ||
TestBed.inject(Meta).getTags('name="dummy"') | ||
|
||
afterEach(() => { | ||
getDummyMetaElements().forEach((element) => element.remove()) | ||
}) | ||
|
||
describe('when no elements exist', () => { | ||
describe('when no contents are provided', () => { | ||
const TEST_CASES = [ | ||
[[], 'empty array'], | ||
[undefined, 'undefined'], | ||
] as const | ||
|
||
TEST_CASES.forEach(([testCase, testCaseName]) => { | ||
describe(`like when ${testCaseName}`, () => { | ||
it('should not create any element', () => { | ||
const sut = makeSut() | ||
|
||
sut.set(dummyMetaNameAttribute, testCase) | ||
|
||
expect(getDummyMetaElements()).toHaveSize(0) | ||
}) | ||
}) | ||
}) | ||
}) | ||
|
||
describe('when contents are provided', () => { | ||
describe('when a single content is provided', () => { | ||
it('should create the element', () => { | ||
const sut = makeSut() | ||
sut.set(dummyMetaNameAttribute, dummyMetaContentAttribute) | ||
|
||
const elements = getDummyMetaElements() | ||
expect(elements.length).toBe(1) | ||
const element = elements[0] | ||
expect(htmlAttributesToJson(element.attributes)).toEqual( | ||
dummyMetaAttributes, | ||
) | ||
}) | ||
}) | ||
|
||
describe('when multiple contents are provided', () => { | ||
it('should create an element for each one', () => { | ||
const sut = makeSut() | ||
sut.set(dummyMetaNameAttribute, [ | ||
dummyMetaContentAttribute, | ||
anotherDummyMetaContentAttribute, | ||
]) | ||
|
||
const elements = getDummyMetaElements() | ||
expect( | ||
elements.map((e) => e.attributes).map(htmlAttributesToJson), | ||
).toEqual([dummyMetaAttributes, anotherDummyMetaAttributes]) | ||
}) | ||
}) | ||
}) | ||
}) | ||
|
||
describe('when elements exist', () => { | ||
let sut: NgxMetaElementsService | ||
|
||
beforeEach(() => { | ||
sut = makeSut() | ||
|
||
const dummyNameAttribute = { | ||
[dummyMetaNameAttribute[0]]: dummyMetaNameAttribute[1], | ||
} | ||
TestBed.inject(Meta).addTags([ | ||
{ | ||
...dummyNameAttribute, | ||
content: 'existing-content-1', | ||
}, | ||
{ | ||
...dummyNameAttribute, | ||
content: 'existing-content-2', | ||
}, | ||
] as MetaDefinition[]) | ||
expect(getDummyMetaElements()) | ||
.withContext('test setup: two elements should exist') | ||
.toHaveSize(2) | ||
}) | ||
|
||
describe('when no contents are provided', () => { | ||
const TEST_CASES = [ | ||
[[], 'empty array'], | ||
[undefined, 'undefined'], | ||
] as const | ||
|
||
TEST_CASES.forEach(([testCase, testCaseName]) => { | ||
describe(`like when ${testCaseName}`, () => { | ||
it('should remove them all', () => { | ||
sut.set(dummyMetaNameAttribute, testCase) | ||
|
||
expect(getDummyMetaElements()).toHaveSize(0) | ||
}) | ||
}) | ||
}) | ||
}) | ||
|
||
describe('when contents are provided', () => { | ||
describe('when a single content is provided', () => { | ||
it('should remove existing elements and create the new one', () => { | ||
sut.set(dummyMetaNameAttribute, dummyMetaContentAttribute) | ||
|
||
const elements = getDummyMetaElements() | ||
expect(elements.length).toBe(1) | ||
const element = elements[0] | ||
expect(htmlAttributesToJson(element.attributes)).toEqual( | ||
dummyMetaAttributes, | ||
) | ||
}) | ||
}) | ||
|
||
describe('when multiple contents are provided', () => { | ||
it('should remove existing elements and create new ones', () => { | ||
sut.set(dummyMetaNameAttribute, [ | ||
dummyMetaContentAttribute, | ||
anotherDummyMetaContentAttribute, | ||
yetAnotherDummyMetaContentAttribute, | ||
]) | ||
|
||
expect( | ||
getDummyMetaElements() | ||
.map((e) => e.attributes) | ||
.map(htmlAttributesToJson), | ||
).toEqual([ | ||
dummyMetaAttributes, | ||
anotherDummyMetaAttributes, | ||
yetAnotherDummyMetaAttributes, | ||
]) | ||
}) | ||
}) | ||
}) | ||
}) | ||
}) | ||
|
||
const makeSut = () => TestBed.inject(NgxMetaElementsService) | ||
|
||
export const htmlAttributesToJson = (attributes: NamedNodeMap): object => | ||
[...Array(attributes.length).keys()] | ||
.map((index) => attributes.item(index)) | ||
.map((item) => (item ? { [item.name]: item.value } : {})) | ||
.reduce((acc, curr) => ({ ...acc, ...curr }), {}) |
Oops, something went wrong.