1// Copyright 2020 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5const {assert} = chai;
6
7import {LoadErrorDescription} from '../../../../front_end/host/ResourceLoader.js';
8import {PageResourceLoader} from '../../../../front_end/sdk/PageResourceLoader.js';
9
10interface LoadResult {
11  success: boolean;
12  content: string;
13  errorDescription: LoadErrorDescription;
14}
15
16describe('PageResourceLoader', () => {
17  const loads: Array<{url: string}> = [];
18  const load = (url: string): Promise<LoadResult> => {
19    loads.push({url});
20
21    return Promise.resolve({
22      success: true,
23      content: `${url} - content`,
24      errorDescription: {message: '', statusCode: 0, netError: 0, netErrorName: '', urlValid: true},
25    });
26  };
27
28  const initiator = {target: null, frameId: '123', initiatorUrl: ''};
29
30  beforeEach(() => {
31    loads.length = 0;
32  });
33
34  it('loads resources correctly', async () => {
35    const loader =
36        PageResourceLoader.instance({forceNew: true, loadOverride: load, maxConcurrentLoads: 500, loadTimeout: 30000});
37    const loading = [
38      loader.loadResource('foo1', initiator),
39      loader.loadResource('foo2', initiator),
40      loader.loadResource('foo3', initiator),
41    ];
42
43    assert.deepEqual(loader.getNumberOfResources(), {loading: 3, queued: 0, resources: 3});
44
45    const results = await Promise.all(loading);
46    assert.deepEqual(loads.map(x => x.url), ['foo1', 'foo2', 'foo3']);
47    assert.deepEqual(results.map(x => x.content), ['foo1 - content', 'foo2 - content', 'foo3 - content']);
48    assert.deepEqual(loader.getNumberOfResources(), {loading: 0, queued: 0, resources: 3});
49    const resources = Array.from(loader.getResourcesLoaded().values());
50    assert.isTrue(resources.every(x => x.success));
51  });
52
53  it('deals with page reloads correctly', async () => {
54    const loader =
55        PageResourceLoader.instance({forceNew: true, loadOverride: load, maxConcurrentLoads: 1, loadTimeout: 30000});
56    const loading = [
57      loader.loadResource('foo1', initiator).catch(e => e.message),
58      loader.loadResource('foo2', initiator).catch(e => e.message),
59      loader.loadResource('foo3', initiator).catch(e => e.message),
60    ];
61    assert.deepEqual(loader.getNumberOfResources(), {loading: 3, queued: 2, resources: 3});
62
63    loader._onMainFrameNavigated({
64      data: {
65        isTopFrame() {
66          return true;
67        },
68      },
69    });
70    assert.deepEqual(loader.getNumberOfResources(), {loading: 3, queued: 0, resources: 0});
71
72    const results = await Promise.all(loading);
73    assert.deepEqual(loads.map(x => x.url), ['foo1']);
74    assert.deepEqual(results[0].content, 'foo1 - content');
75    assert.deepEqual(results[1], 'Load canceled due to reload of inspected page');
76    assert.deepEqual(results[2], 'Load canceled due to reload of inspected page');
77  });
78
79  it('handles the load timeout correctly', async () => {
80    const load = (url: string): Promise<LoadResult> => {
81      loads.push({url});
82      return new Promise(() => {});
83    };
84
85    const loader =
86        PageResourceLoader.instance({forceNew: true, loadOverride: load, maxConcurrentLoads: 2, loadTimeout: 30});
87    const loading = [
88      loader.loadResource('foo1', initiator).catch(e => e.message),
89      loader.loadResource('foo2', initiator).catch(e => e.message),
90      loader.loadResource('foo3', initiator).catch(e => e.message),
91    ];
92    assert.deepEqual(loader.getNumberOfResources(), {loading: 3, queued: 1, resources: 3});
93
94    const results = await Promise.all(loading);
95    assert.deepEqual(loads.map(x => x.url), ['foo1', 'foo2', 'foo3']);
96    const resources = Array.from(loader.getResourcesLoaded().values());
97    assert.isTrue(resources.every(x => !x.success), 'All resources should have failed to load');
98    assert.isTrue(
99        results.every(x => x === 'Load canceled due to load timeout'),
100        'All loads should have a exceeded the load timeout');
101    assert.deepEqual(loader.getNumberOfResources(), {loading: 0, queued: 0, resources: 3});
102  });
103
104  it('respects the max concurrent loads', async () => {
105    const loader =
106        PageResourceLoader.instance({forceNew: true, loadOverride: load, maxConcurrentLoads: 2, loadTimeout: 30});
107    const loading = [
108      loader.loadResource('foo1', initiator),
109      loader.loadResource('foo2', initiator),
110      loader.loadResource('foo3', initiator),
111    ];
112    assert.deepEqual(loader.getNumberOfResources(), {loading: 3, queued: 1, resources: 3});
113
114    const results = await Promise.all(loading);
115    assert.deepEqual(loads.map(x => x.url), ['foo1', 'foo2', 'foo3']);
116    assert.deepEqual(results.map(x => x.content), ['foo1 - content', 'foo2 - content', 'foo3 - content']);
117    assert.deepEqual(loader.getNumberOfResources(), {loading: 0, queued: 0, resources: 3});
118    const resources = Array.from(loader.getResourcesLoaded().values());
119    assert.isTrue(resources.every(x => x.success));
120  });
121});
122