summaryrefslogtreecommitdiffstats
path: root/devtools/client/debugger/test/mochitest/browser_dbg-reducer-cleanup-on-target-removal.js
blob: ad7ff57f2a038d32f246a943c5469f8eab9935f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */

// Verify that reducers are cleared on target removal

"use strict";

const testServer = createVersionizedHttpTestServer(
  "examples/sourcemaps-reload-uncompressed"
);
const IFRAME_TEST_URL = testServer.urlFor("index.html");

// Embed the integration test page into an iframe
const TEST_URI = `https://example.com/document-builder.sjs?html=
<iframe src="${encodeURI(IFRAME_TEST_URL)}"></iframe><body>`;

add_task(async function () {
  if (!isEveryFrameTargetEnabled()) {
    ok(true, "This test is disabled without EFT");
    return;
  }
  await pushPref("devtools.debugger.map-scopes-enabled", true);
  const dbg = await initDebuggerWithAbsoluteURL(TEST_URI);

  const frameBC = await SpecialPowers.spawn(
    gBrowser.selectedBrowser,
    [],
    function () {
      return content.document.querySelector("iframe").browsingContext;
    }
  );

  info("Pause on an original source to ensure filling the reducers");
  await waitForSource(dbg, "original.js");
  await selectSource(dbg, "original.js");
  await addBreakpoint(dbg, "original.js", 8);

  // The following task will never resolve as the call to foo()
  // will be paused and never released
  PromiseTestUtils.allowMatchingRejectionsGlobally(
    /Actor 'SpecialPowers' destroyed before query 'Spawn'/
  );
  SpecialPowers.spawn(frameBC, [], function () {
    return content.wrappedJSObject.foo();
  });

  await waitForPaused(dbg, "original.js");
  assertPausedAtSourceAndLine(dbg, findSource(dbg, "original.js").id, 8);
  // Also open the genertated source to populate the reducer for original and generated sources
  await dbg.actions.jumpToMappedSelectedLocation();
  await waitForSelectedSource(dbg, "bundle.js");

  // Assert that reducer do have some data before remove the target.
  Assert.greater(dbg.selectors.getSourceCount(), 0, "Some sources exists");
  is(dbg.selectors.getBreakpointCount(), 1, "There is one breakpoint");
  is(dbg.selectors.getSourceTabs().length, 2, "Two tabs are opened");
  Assert.greater(
    dbg.selectors.getAllThreads().length,
    1,
    "There is many targets/threads involved by the intergration test"
  );
  ok(
    !!dbg.selectors.getSourcesTreeSources().length,
    "There is sources displayed in the SourceTree"
  );
  is(
    dbg.selectors.getSelectedLocation().source.id,
    findSource(dbg, "bundle.js").id,
    "The generated source is reporeted as selected"
  );
  ok(!!dbg.selectors.getFocusedSourceItem(), "Has a focused source tree item");
  Assert.greater(
    dbg.selectors.getExpandedState().size,
    0,
    "Has some expanded source tree items"
  );

  // But also directly querying the reducer states, as we don't necessarily
  // have selectors exposing their raw internals
  let state = dbg.store.getState();
  ok(
    !!Object.keys(state.ast.mutableOriginalSourcesSymbols).length,
    "Some symbols for original sources exists"
  );
  ok(
    !!Object.keys(state.ast.mutableSourceActorSymbols).length,
    "Some symbols for generated sources exists"
  );
  ok(!!Object.keys(state.ast.mutableInScopeLines).length, "Some scopes exists");
  Assert.greater(
    state.sourceActors.mutableSourceActors.size,
    0,
    "Some source actor exists"
  );
  Assert.greater(
    state.sourceActors.mutableBreakableLines.size,
    0,
    "Some breakable line exists"
  );
  Assert.greater(
    state.sources.mutableBreakpointPositions.size,
    0,
    "Some breakable positions exists"
  );
  Assert.greater(
    state.sources.mutableOriginalBreakableLines.size,
    0,
    "Some original breakable lines exists"
  );

  info("Remove the iframe");
  await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function () {
    content.document.querySelector("iframe").remove();
  });

  info("Wait for all sources to be removed");
  await waitFor(() => dbg.selectors.getSourceCount() == 0);
  // The pause thread being removed, we are no longer paused.
  assertNotPaused(dbg);

  // Assert they largest reducer data is cleared on thread removal

  // First via common selectors
  is(dbg.selectors.getSourceCount(), 0, "No sources exists");
  is(dbg.selectors.getBreakpointCount(), 0, "No breakpoints exists");
  is(dbg.selectors.getSourceTabs().length, 0, "No tabs exists");
  is(
    dbg.selectors.getAllThreads().length,
    1,
    "There is only the top level target/thread"
  );
  is(
    dbg.selectors.getSourcesTreeSources().length,
    0,
    "There is no source in the SourceTree"
  );
  is(
    dbg.selectors.getSelectedLocation(),
    null,
    "Selected location is nullified as the selected source has been removed"
  );
  ok(!dbg.selectors.getFocusedSourceItem(), "No more focused source tree item");
  is(
    dbg.selectors.getExpandedState().size,
    0,
    "No more expanded source tree items"
  );

  // But also directly querying the reducer states, as we don't necessarily
  // have selectors exposing their raw internals
  state = dbg.store.getState();
  is(
    Object.keys(state.ast.mutableOriginalSourcesSymbols).length,
    0,
    "No symbols for original sources exists"
  );
  is(
    Object.keys(state.ast.mutableSourceActorSymbols).length,
    0,
    "No symbols for generated sources exists"
  );
  is(Object.keys(state.ast.mutableInScopeLines).length, 0, "No scopes exists");
  is(state.sourceActors.mutableSourceActors.size, 0, "No source actor exists");
  is(
    state.sourceActors.mutableBreakableLines.size,
    0,
    "No breakable line exists"
  );
  is(
    state.sources.mutableBreakpointPositions.size,
    0,
    "No breakable positions exists"
  );
  is(
    state.sources.mutableOriginalBreakableLines.size,
    0,
    "No original breakable lines exists"
  );
});