Skip to content

Commit 045c8b9

Browse files
committed
test: add Phase 3 audit fixture translating iframe-title peer cases
Translates 33 cases from peer-plugin rules: - jsx-a11y iframe-has-title - vuejs-accessibility iframe-has-title - lit-a11y iframe-title Fixture documents parity after this fix: - title={{null|undefined|number}} and concat `title="{{null}}"` / `title="{{42}}"` are now flagged via dynamicFalseTitle. Remaining divergences (title={{""}} still accepted, aria-hidden / hidden exemption, whitespace-only title over-flagged, duplicate-title detection inherited from ember-template-lint) are annotated inline.
1 parent 54955c2 commit 045c8b9

1 file changed

Lines changed: 209 additions & 0 deletions

File tree

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
// Audit fixture — peer-plugin parity for `ember/template-require-iframe-title`.
2+
// These tests are NOT part of the main suite and do not run in CI. They encode
3+
// the CURRENT behavior of our rule so that running this file reports pass.
4+
// Each divergence from an upstream plugin is annotated as "DIVERGENCE —".
5+
//
6+
// Source files (context/ checkouts):
7+
// - eslint-plugin-jsx-a11y-main/__tests__/src/rules/iframe-has-title-test.js
8+
// - eslint-plugin-vuejs-accessibility-main/src/rules/__tests__/iframe-has-title.test.ts
9+
// - eslint-plugin-lit-a11y/tests/lib/rules/iframe-title.js
10+
11+
'use strict';
12+
13+
const rule = require('../../../lib/rules/template-require-iframe-title');
14+
const RuleTester = require('eslint').RuleTester;
15+
16+
const ruleTester = new RuleTester({
17+
parser: require.resolve('ember-eslint-parser'),
18+
parserOptions: { ecmaVersion: 2022, sourceType: 'module' },
19+
});
20+
21+
ruleTester.run('audit:iframe-title (gts)', rule, {
22+
valid: [
23+
// === Upstream parity — basic cases ===
24+
// jsx-a11y / vue-a11y / lit-a11y: valid (no iframe, or titled iframe).
25+
'<template><div /></template>',
26+
'<template><iframe title="Unique title" /></template>',
27+
28+
// Dynamic title — jsx-a11y treats `title={foo}` as valid (expression is
29+
// assumed to yield a truthy string). vue-a11y: valid for `:title="foo"`.
30+
// lit-a11y: valid for `title=${foo}`. Ours: valid for `{{someValue}}`.
31+
'<template><iframe title={{someValue}} /></template>',
32+
33+
// Ours: valid for concat-mustache (dynamic in concat).
34+
// No direct jsx-a11y analogue because JSX has no string-interpolation; but
35+
// the equivalent `title={`${foo}`}` is treated as valid by jsx-a11y.
36+
'<template><iframe title="{{someValue}}" /></template>',
37+
38+
// === OUR behavior (no upstream peer equivalent) — exemptions ===
39+
// Our rule skips iframes that are aria-hidden or hidden.
40+
// - jsx-a11y: does NOT exempt aria-hidden; `<iframe aria-hidden />`
41+
// without a title is still flagged.
42+
// - vue-a11y / lit-a11y: same — no aria-hidden/hidden exemption.
43+
// Intentional: matches ember-template-lint upstream behavior.
44+
'<template><iframe aria-hidden="true" /></template>',
45+
'<template><iframe hidden /></template>',
46+
'<template><iframe title="" aria-hidden /></template>',
47+
'<template><iframe title="" hidden /></template>',
48+
49+
// === Remaining divergence — `title={{""}}` ===
50+
// jsx-a11y flags `<iframe title={""} />` via getLiteralPropValue.
51+
// Our rule inspects only GlimmerBooleanLiteral / GlimmerNullLiteral /
52+
// GlimmerUndefinedLiteral / GlimmerNumberLiteral — an empty-string
53+
// literal inside `{{}}` is not a GlimmerStringLiteral AST node but
54+
// a concat-of-nothing; we under-flag here.
55+
'<template><iframe title={{""}} /></template>',
56+
57+
// === Disambiguation — distinct titles across iframes (all valid) ===
58+
'<template><iframe title="foo" /><iframe title="bar" /></template>',
59+
],
60+
61+
invalid: [
62+
// === Upstream parity — missing title ===
63+
{
64+
code: '<template><iframe /></template>',
65+
output: null,
66+
errors: [{ messageId: 'missingTitle' }],
67+
},
68+
{
69+
code: '<template><iframe src="/content"></iframe></template>',
70+
output: null,
71+
errors: [{ messageId: 'missingTitle' }],
72+
},
73+
74+
// === Upstream parity — empty title string ===
75+
// jsx-a11y, vue-a11y, lit-a11y all flag `title=""`.
76+
{
77+
code: '<template><iframe title="" /></template>',
78+
output: null,
79+
errors: [{ messageId: 'emptyTitle' }],
80+
},
81+
// Whitespace-only title — ours trims then flags empty.
82+
// jsx-a11y: `getLiteralPropValue(" ")` yields " " which is truthy, so
83+
// jsx-a11y would NOT flag. vue-a11y similarly does not trim. Ours trims.
84+
// DIVERGENCE — we over-flag whitespace-only titles.
85+
{
86+
code: '<template><iframe title=" " /></template>',
87+
output: null,
88+
errors: [{ messageId: 'emptyTitle' }],
89+
},
90+
91+
// === Parity — title is literal boolean / null / undefined / number ===
92+
// jsx-a11y: INVALID for any non-string literal (via getLiteralPropValue
93+
// truthiness + string-check). vue-a11y: same. Our rule now rejects
94+
// GlimmerBooleanLiteral / GlimmerNullLiteral / GlimmerUndefinedLiteral
95+
// / GlimmerNumberLiteral in both `{{}}` and `"{{}}"` positions.
96+
{
97+
code: '<template><iframe title={{false}} /></template>',
98+
output: null,
99+
errors: [{ messageId: 'dynamicFalseTitle' }],
100+
},
101+
{
102+
code: '<template><iframe title={{true}} /></template>',
103+
output: null,
104+
errors: [{ messageId: 'dynamicFalseTitle' }],
105+
},
106+
{
107+
code: '<template><iframe title={{null}} /></template>',
108+
output: null,
109+
errors: [{ messageId: 'dynamicFalseTitle' }],
110+
},
111+
{
112+
code: '<template><iframe title={{undefined}} /></template>',
113+
output: null,
114+
errors: [{ messageId: 'dynamicFalseTitle' }],
115+
},
116+
{
117+
code: '<template><iframe title={{42}} /></template>',
118+
output: null,
119+
errors: [{ messageId: 'dynamicFalseTitle' }],
120+
},
121+
// Concat form — `title="{{false}}"` / etc. also flagged.
122+
{
123+
code: '<template><iframe title="{{false}}" /></template>',
124+
output: null,
125+
errors: [{ messageId: 'dynamicFalseTitle' }],
126+
},
127+
{
128+
code: '<template><iframe title="{{null}}" /></template>',
129+
output: null,
130+
errors: [{ messageId: 'dynamicFalseTitle' }],
131+
},
132+
{
133+
code: '<template><iframe title="{{42}}" /></template>',
134+
output: null,
135+
errors: [{ messageId: 'dynamicFalseTitle' }],
136+
},
137+
138+
// === DIVERGENCE — duplicate-title detection ===
139+
// jsx-a11y, vue-a11y, lit-a11y: do NOT check for duplicate titles across
140+
// multiple iframes. Our rule does (inherited from ember-template-lint).
141+
// Captured here as one of our OVER-flagging cases (intentional extension).
142+
{
143+
code: '<template><iframe title="foo" /><iframe title="foo" /></template>',
144+
output: null,
145+
errors: [
146+
{ message: 'This title is not unique. #1' },
147+
{
148+
message:
149+
'<iframe> elements must have a unique title property. Value title="foo" already used for different iframe. #1',
150+
},
151+
],
152+
},
153+
],
154+
});
155+
156+
const hbsRuleTester = new RuleTester({
157+
parser: require.resolve('ember-eslint-parser/hbs'),
158+
parserOptions: { ecmaVersion: 2022, sourceType: 'module' },
159+
});
160+
161+
hbsRuleTester.run('audit:iframe-title (hbs)', rule, {
162+
valid: [
163+
'<iframe title="Welcome" />',
164+
'<iframe title={{someValue}} />',
165+
// DIVERGENCE — exempted (see gts section)
166+
'<iframe aria-hidden="true" />',
167+
'<iframe hidden />',
168+
],
169+
invalid: [
170+
{
171+
code: '<iframe />',
172+
output: null,
173+
errors: [{ messageId: 'missingTitle' }],
174+
},
175+
{
176+
code: '<iframe title="" />',
177+
output: null,
178+
errors: [{ messageId: 'emptyTitle' }],
179+
},
180+
// Parity — non-string literal titles.
181+
{
182+
code: '<iframe title={{false}} />',
183+
output: null,
184+
errors: [{ messageId: 'dynamicFalseTitle' }],
185+
},
186+
{
187+
code: '<iframe title={{undefined}} />',
188+
output: null,
189+
errors: [{ messageId: 'dynamicFalseTitle' }],
190+
},
191+
{
192+
code: '<iframe title={{42}} />',
193+
output: null,
194+
errors: [{ messageId: 'dynamicFalseTitle' }],
195+
},
196+
// DIVERGENCE — duplicate detection (upstream does not check).
197+
{
198+
code: '<iframe title="foo" /><iframe title="foo" />',
199+
output: null,
200+
errors: [
201+
{ message: 'This title is not unique. #1' },
202+
{
203+
message:
204+
'<iframe> elements must have a unique title property. Value title="foo" already used for different iframe. #1',
205+
},
206+
],
207+
},
208+
],
209+
});

0 commit comments

Comments
 (0)