Skip to content

Commit 4aa60b7

Browse files
committed
Merge remote-tracking branch 'upstream/main' into web-core-tests-in-1p
2 parents 2942210 + 6fd71ab commit 4aa60b7

42 files changed

Lines changed: 6194 additions & 1759 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

renderers/angular/a2ui_explorer/src/app/tests/utils/test_utils.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,41 @@
1616

1717
import {TestBed} from '@angular/core/testing';
1818
import {DemoComponent} from '../../demo.component';
19-
import {EXAMPLES} from '../../generated/examples-bundle';
19+
import {EXAMPLES_V08, EXAMPLES_V09} from '../../generated/examples-bundle';
2020
import {provideMarkdownRenderer} from '../../../../../src/v0_9/core/markdown';
2121
import {A2UI_VERSION, Version} from '../../types';
2222

23+
export {Version};
24+
2325
/**
2426
* Helper function to load an example in the DemoComponent for testing.
2527
* Resolves after the example is selected and initial async rendering has time to complete.
2628
*/
27-
export async function loadExample(exampleName: string) {
29+
export async function loadExample(exampleName: string, version: Version = Version.V0_9) {
2830
await TestBed.configureTestingModule({
2931
imports: [DemoComponent],
30-
providers: [provideMarkdownRenderer(), {provide: A2UI_VERSION, useValue: Version.V0_9}],
32+
providers: [
33+
provideMarkdownRenderer(),
34+
{
35+
provide: A2UI_VERSION,
36+
useValue: version,
37+
},
38+
],
3139
});
3240

3341
const fixture = TestBed.createComponent(DemoComponent);
3442
const component = fixture.componentInstance;
3543
fixture.detectChanges();
3644

37-
const example = EXAMPLES.find(ex => ex.name === exampleName);
45+
const examples = version === Version.V0_9 ? EXAMPLES_V09 : EXAMPLES_V08;
46+
let example = examples.find(ex => ex.name === exampleName);
47+
48+
if (version === Version.V0_8 && !example) {
49+
example =
50+
examples.find(ex => ex.name === `${exampleName} (basic)`) ||
51+
examples.find(ex => ex.name === `${exampleName} (minimal)`);
52+
}
53+
3854
expect(example).withContext(`Example not found: ${exampleName}`).toBeTruthy();
3955

4056
component.selectExample(example!);
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import {ComponentFixture} from '@angular/core/testing';
18+
import {DemoComponent} from '../../demo.component';
19+
import {Version, getCanvas, loadExample} from '../utils/test_utils';
20+
21+
describe('Example: Flight Status (v0.8)', () => {
22+
let fixture: ComponentFixture<DemoComponent>;
23+
let textContent: string;
24+
25+
beforeEach(async () => {
26+
fixture = await loadExample('Flight Status', Version.V0_8);
27+
textContent = getCanvas().textContent;
28+
});
29+
30+
it('should render flight details', async () => {
31+
expect(textContent).toContain('OS 87');
32+
expect(textContent).toContain('Vienna');
33+
expect(textContent).toContain('→');
34+
expect(textContent).toContain('New York');
35+
});
36+
37+
it('should render labels', async () => {
38+
expect(textContent).toContain('Departs');
39+
expect(textContent).toContain('Arrives');
40+
expect(textContent).toContain('Status');
41+
expect(textContent).toContain('On Time');
42+
});
43+
44+
it('should render icon', async () => {
45+
const iconInnerEl = fixture.nativeElement.querySelector('.g-icon');
46+
expect(iconInnerEl).toBeTruthy();
47+
expect(iconInnerEl.textContent.trim()).toBe('send');
48+
});
49+
});
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import {ComponentFixture} from '@angular/core/testing';
18+
import {DemoComponent} from '../../demo.component';
19+
import {Version, getCanvas, loadExample, wait} from '../utils/test_utils';
20+
21+
describe('Example: Email Compose (v0.8)', () => {
22+
let textContent: string;
23+
let fixture: ComponentFixture<DemoComponent>;
24+
25+
beforeEach(async () => {
26+
fixture = await loadExample('Email Compose', Version.V0_8);
27+
textContent = getCanvas().textContent;
28+
});
29+
30+
it('should render email headers', async () => {
31+
expect(textContent).toContain('FROM');
32+
expect(textContent).toContain('alex@acme.com');
33+
expect(textContent).toContain('TO');
34+
expect(textContent).toContain('jordan@acme.com');
35+
expect(textContent).toContain('SUBJECT');
36+
expect(textContent).toContain('Q4 Revenue Forecast');
37+
});
38+
39+
it('should render email body', async () => {
40+
expect(textContent).toContain('Hi Jordan,');
41+
expect(textContent).toContain('Following up on our call');
42+
expect(textContent).toContain('Best,');
43+
expect(textContent).toContain('Alex');
44+
});
45+
46+
it('should render buttons', async () => {
47+
expect(textContent).toContain('Send email');
48+
expect(textContent).toContain('Discard');
49+
});
50+
51+
it('should dispatch send action on button click', async () => {
52+
const component = fixture.componentInstance;
53+
54+
const sendBtn = fixture.nativeElement.querySelector('a2ui-button button');
55+
expect(sendBtn).toBeTruthy();
56+
57+
sendBtn.click();
58+
fixture.detectChanges();
59+
60+
await wait(10);
61+
62+
expect(component.eventsLog.length).toBeGreaterThan(0);
63+
const loggedAction = component.eventsLog[0].action;
64+
expect(loggedAction.name).toBe('send');
65+
});
66+
67+
it('should dispatch discard action on button click', async () => {
68+
const component = fixture.componentInstance;
69+
70+
const buttons = fixture.nativeElement.querySelectorAll('a2ui-button button');
71+
expect(buttons.length).toBeGreaterThan(1);
72+
const discardBtn = buttons[1];
73+
expect(discardBtn).toBeTruthy();
74+
75+
discardBtn.click();
76+
fixture.detectChanges();
77+
78+
await wait(10);
79+
80+
expect(component.eventsLog.length).toBeGreaterThan(0);
81+
const loggedAction = component.eventsLog[0].action;
82+
expect(loggedAction.name).toBe('discard');
83+
});
84+
});
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import {ComponentFixture} from '@angular/core/testing';
18+
import {DemoComponent} from '../../demo.component';
19+
import {Version, getCanvas, loadExample, wait} from '../utils/test_utils';
20+
21+
describe('Example: Calendar Day (basic) (v0.8)', () => {
22+
let textContent: string;
23+
let fixture: ComponentFixture<DemoComponent>;
24+
25+
beforeEach(async () => {
26+
fixture = await loadExample('Calendar Day (basic)', Version.V0_8);
27+
textContent = getCanvas().textContent;
28+
});
29+
30+
it('should render expected text content', async () => {
31+
expect(textContent).toContain('Add to calendar');
32+
expect(textContent).toContain('Discard');
33+
expect(textContent).toContain('Friday');
34+
expect(textContent).toContain('28');
35+
expect(textContent).toContain('Lunch');
36+
expect(textContent).toContain('12:00 - 12:45 PM');
37+
expect(textContent).toContain('Q1 roadmap review');
38+
expect(textContent).toContain('1:00 - 2:00 PM');
39+
expect(textContent).toContain('Team standup');
40+
expect(textContent).toContain('3:30 - 4:00 PM');
41+
});
42+
43+
it('should dispatch add action on button click', async () => {
44+
const component = fixture.componentInstance;
45+
46+
const buttons = fixture.nativeElement.querySelectorAll('a2ui-button button');
47+
expect(buttons.length).toBeGreaterThan(0);
48+
const btn = buttons[0];
49+
expect(btn).toBeTruthy();
50+
51+
btn.click();
52+
fixture.detectChanges();
53+
54+
await wait(10);
55+
56+
expect(component.eventsLog.length).toBeGreaterThan(0);
57+
const loggedAction = component.eventsLog[0].action;
58+
expect(loggedAction.name).toBe('add');
59+
});
60+
61+
it('should dispatch discard action on button click', async () => {
62+
const component = fixture.componentInstance;
63+
64+
const buttons = fixture.nativeElement.querySelectorAll('a2ui-button button');
65+
expect(buttons.length).toBeGreaterThan(1);
66+
const btn = buttons[1];
67+
expect(btn).toBeTruthy();
68+
69+
btn.click();
70+
fixture.detectChanges();
71+
72+
await wait(10);
73+
74+
expect(component.eventsLog.length).toBeGreaterThan(0);
75+
const loggedAction = component.eventsLog[0].action;
76+
expect(loggedAction.name).toBe('discard');
77+
});
78+
});
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import {Version, getCanvas, loadExample} from '../utils/test_utils';
18+
19+
describe('Example: Weather Current (basic) (v0.8)', () => {
20+
let textContent: string;
21+
22+
beforeEach(async () => {
23+
await loadExample('Weather Current (basic)', Version.V0_8);
24+
textContent = getCanvas().textContent;
25+
});
26+
27+
it('should render expected text content', async () => {
28+
expect(textContent).toContain('72°');
29+
expect(textContent).toContain('58°');
30+
expect(textContent).toContain('Austin, TX');
31+
expect(textContent).toContain('Clear skies with light breeze');
32+
33+
// Check for emojis in forecast
34+
expect(textContent).toContain('\u2600\ufe0f'); // ☀️
35+
expect(textContent).toContain('\u26c5'); // ⛅
36+
});
37+
});
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import {ComponentFixture} from '@angular/core/testing';
18+
import {DemoComponent} from '../../demo.component';
19+
import {Version, getCanvas, loadExample, wait} from '../utils/test_utils';
20+
21+
describe('Example: Product Card (basic) (v0.8)', () => {
22+
let textContent: string;
23+
let fixture: ComponentFixture<DemoComponent>;
24+
25+
beforeEach(async () => {
26+
fixture = await loadExample('Product Card (basic)', Version.V0_8);
27+
textContent = getCanvas().textContent;
28+
});
29+
30+
it('should render expected text content', async () => {
31+
expect(textContent).toContain('Add to Cart');
32+
expect(textContent).toContain('Wireless Headphones Pro');
33+
expect(textContent).toContain('★★★★★');
34+
expect(textContent).toContain('(2,847 reviews)');
35+
expect(textContent).toContain('$199.99');
36+
expect(textContent).toContain('$249.99');
37+
});
38+
39+
it('should dispatch addToCart action on button click', async () => {
40+
const component = fixture.componentInstance;
41+
42+
const buttons = fixture.nativeElement.querySelectorAll('a2ui-button button');
43+
expect(buttons.length).toBeGreaterThan(0);
44+
const btn = buttons[0];
45+
expect(btn).toBeTruthy();
46+
47+
btn.click();
48+
fixture.detectChanges();
49+
50+
await wait(10);
51+
52+
expect(component.eventsLog.length).toBeGreaterThan(0);
53+
const loggedAction = component.eventsLog[0].action;
54+
expect(loggedAction.name).toBe('addToCart');
55+
});
56+
});

0 commit comments

Comments
 (0)