Skip to content

Commit 80c0c70

Browse files
authored
Minimal integration test for dartdoc search bar. (#8056)
1 parent 1e3830b commit 80c0c70

File tree

3 files changed

+97
-23
lines changed

3 files changed

+97
-23
lines changed

pkg/pub_integration/lib/src/test_browser.dart

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -182,13 +182,23 @@ class TestBrowserSession {
182182
await rq.continueRequest();
183183
return;
184184
}
185+
// TODO: this file is missing, we may need to fix it in the dartdoc stylesheet
186+
if (rq.url.endsWith('/css/search.svg')) {
187+
await rq.respond(
188+
status: 200,
189+
body: '',
190+
contentType: 'image/svg+xml',
191+
headers: {'Cache-Control': 'public, max-age=604800'},
192+
);
193+
return;
194+
}
185195

186196
final uri = Uri.parse(rq.url);
187197
if (uri.path.contains('//')) {
188198
serverErrors.add('Double-slash URL detected: "${rq.url}".');
189199
}
190200

191-
await rq.continueRequest(headers: rq.headers);
201+
await rq.continueRequest();
192202
});
193203

194204
page.onResponse.listen((rs) async {
@@ -209,21 +219,29 @@ class TestBrowserSession {
209219
try {
210220
parseAndValidateHtml(await rs.text);
211221
} catch (e) {
212-
serverErrors.add('${rs.request.url} returned bad HTML: $e');
222+
final url = rs.request.url;
223+
if (url.contains('/documentation/') &&
224+
url.endsWith('-sidebar.html')) {
225+
// ignore dartdoc sidebars
226+
} else {
227+
serverErrors.add('$url returned bad HTML: $e');
228+
}
213229
}
214230
}
215231

216-
final uri = Uri.parse(rs.url);
217-
if (uri.pathSegments.length > 1 && uri.pathSegments.first == 'static') {
218-
if (!uri.pathSegments[1].startsWith('hash-')) {
219-
serverErrors.add('Static ${rs.url} is without hash URL.');
220-
}
221-
222-
final cacheHeader = rs.headers[HttpHeaders.cacheControlHeader];
223-
if (cacheHeader == null ||
224-
!cacheHeader.contains('public') ||
225-
!cacheHeader.contains('max-age')) {
226-
serverErrors.add('Static ${rs.url} is without public caching.');
232+
if (!rs.url.startsWith('data:')) {
233+
final uri = Uri.parse(rs.url);
234+
if (uri.pathSegments.length > 1 && uri.pathSegments.first == 'static') {
235+
if (!uri.pathSegments[1].startsWith('hash-')) {
236+
serverErrors.add('Static ${rs.url} is without hash URL.');
237+
}
238+
239+
final cacheHeader = rs.headers[HttpHeaders.cacheControlHeader];
240+
if (cacheHeader == null ||
241+
!cacheHeader.contains('public') ||
242+
!cacheHeader.contains('max-age')) {
243+
serverErrors.add('Static ${rs.url} is without public caching.');
244+
}
227245
}
228246
}
229247
});
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'dart:convert';
6+
7+
import 'package:http/http.dart' as http;
8+
import 'package:pub_integration/src/fake_test_context_provider.dart';
9+
import 'package:pub_integration/src/test_browser.dart';
10+
import 'package:puppeteer/puppeteer.dart';
11+
import 'package:test/test.dart';
12+
13+
void main() {
14+
group('dartdoc search', () {
15+
late final TestContextProvider fakeTestScenario;
16+
final httpClient = http.Client();
17+
18+
setUpAll(() async {
19+
fakeTestScenario = await TestContextProvider.start();
20+
});
21+
22+
tearDownAll(() async {
23+
await fakeTestScenario.close();
24+
httpClient.close();
25+
});
26+
27+
test('bulk tests', () async {
28+
final origin = fakeTestScenario.pubHostedUrl;
29+
// Importing one package + local analysis
30+
await httpClient.post(Uri.parse('$origin/fake-test-profile'),
31+
body: json.encode({
32+
'testProfile': {
33+
'defaultUser': '[email protected]',
34+
'packages': [
35+
{'name': 'oxygen'},
36+
],
37+
},
38+
'analysis': 'local',
39+
}));
40+
41+
final user = await fakeTestScenario.createAnonymousTestUser();
42+
43+
// test keyboard navigation
44+
await user.withBrowserPage((page) async {
45+
await page.gotoOrigin('/documentation/oxygen/latest/');
46+
47+
await page.keyboard.press(Key.slash);
48+
await Future.delayed(Duration(milliseconds: 200));
49+
await page.keyboard.type('enum');
50+
await Future.delayed(Duration(milliseconds: 200));
51+
await page.keyboard.press(Key.arrowDown);
52+
await Future.delayed(Duration(milliseconds: 200));
53+
await page.keyboard.press(Key.enter);
54+
55+
await page.waitForNavigation();
56+
57+
// It is likely that we end up on the `TypeEnum.html` page, but we don't
58+
// need to hardcode it here, in case dartdoc changes the order of the options.
59+
expect(page.url,
60+
startsWith('$origin/documentation/oxygen/latest/oxygen/'));
61+
expect(page.url, endsWith('.html'));
62+
});
63+
});
64+
}, timeout: Timeout.factor(testTimeoutFactor));
65+
}

pkg/pub_integration/test/search_completition_test.dart

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,7 @@ void main() {
2626

2727
test('bulk tests', () async {
2828
final origin = fakeTestScenario.pubHostedUrl;
29-
// init server data
30-
//
31-
// The test profile import uses a fake analysis by default, which
32-
// assigns tags with a pseudorandom process (based on the hash of the
33-
// package's name and sometimes the version), with a few hardcoded
34-
// patterns, e.g. `flutter_*` packages will get `sdk:flutter` tag assigned.
35-
//
36-
// This imports 100 packages with these semi-random tags, and adding and
37-
// removing filters works because of the number of packages and their
38-
// tags are kind of random.
29+
// Importing one package + local analysis
3930
await httpClient.post(Uri.parse('$origin/fake-test-profile'),
4031
body: json.encode({
4132
'testProfile': {

0 commit comments

Comments
 (0)