summaryrefslogtreecommitdiffstats
path: root/devtools/client/webconsole/test/browser/browser_webconsole_persist.js
blob: 08fa17d62918d544dfbe7d7e13be4627331432e1 (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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

// Check that message persistence works - bug 705921 / bug 1307881

"use strict";

const TEST_FILE = "test-console.html";
const TEST_COM_URI = URL_ROOT_COM_SSL + TEST_FILE;
const TEST_ORG_URI = URL_ROOT_ORG_SSL + TEST_FILE;
// TEST_MOCHI_URI uses a non standart port and hence
// is not subject to https-first mode
const TEST_MOCHI_URI = URL_ROOT_MOCHI_8888 + TEST_FILE;

registerCleanupFunction(() => {
  Services.prefs.clearUserPref("devtools.webconsole.persistlog");
});

const INITIAL_LOGS_NUMBER = 5;

const {
  MESSAGE_TYPE,
} = require("resource://devtools/client/webconsole/constants.js");
const {
  WILL_NAVIGATE_TIME_SHIFT,
} = require("resource://devtools/server/actors/webconsole/listeners/document-events.js");

async function logAndAssertInitialMessages(hud) {
  await SpecialPowers.spawn(
    gBrowser.selectedBrowser,
    [INITIAL_LOGS_NUMBER],
    count => {
      content.wrappedJSObject.doLogs(count);
    }
  );
  await waitFor(() => findAllMessages(hud).length === INITIAL_LOGS_NUMBER);
  ok(true, "Messages showed up initially");
}

add_task(async function () {
  info("Testing that messages disappear on a refresh if logs aren't persisted");
  const hud = await openNewTabAndConsole(TEST_COM_URI);

  await logAndAssertInitialMessages(hud);

  const onReloaded = hud.ui.once("reloaded");
  await reloadBrowser();
  await onReloaded;

  info("Wait for messages to be cleared");
  await waitFor(() => findAllMessages(hud).length === 0);
  ok(true, "Messages disappeared");

  await closeToolbox();
});

add_task(async function () {
  info(
    "Testing that messages disappear on a cross origin navigation if logs aren't persisted"
  );
  const hud = await openNewTabAndConsole(TEST_COM_URI);

  await logAndAssertInitialMessages(hud);

  await navigateTo(TEST_ORG_URI);
  await waitFor(() => findAllMessages(hud).length === 0);
  ok(true, "Messages disappeared");

  await closeToolbox();
});

add_task(async function () {
  info("Testing that messages disappear on bfcache navigations");
  const firstLocation =
    "data:text/html,<!DOCTYPE html><script>console.log('first document load');window.onpageshow=()=>console.log('first document show');</script>";
  const secondLocation =
    "data:text/html,<!DOCTYPE html><script>console.log('second document load');window.onpageshow=()=>console.log('second document show');</script>";
  const hud = await openNewTabAndConsole(firstLocation);

  info("Wait for first page messages");
  // Look into .message-body as the default selector also include the frame,
  // which is the document url, which also include the logged string...
  await waitFor(
    () =>
      findMessagePartsByType(hud, {
        text: "first document load",
        typeSelector: ".console-api",
        partSelector: ".message-body",
      }).length === 1 &&
      findMessagePartsByType(hud, {
        text: "first document show",
        typeSelector: ".console-api",
        partSelector: ".message-body",
      }).length === 1
  );
  const firstPageInnerWindowId =
    gBrowser.selectedBrowser.browsingContext.currentWindowGlobal.innerWindowId;

  await navigateTo(secondLocation);

  const secondPageInnerWindowId =
    gBrowser.selectedBrowser.browsingContext.currentWindowGlobal.innerWindowId;
  isnot(
    firstPageInnerWindowId,
    secondPageInnerWindowId,
    "The second page is having a distinct inner window id"
  );
  await waitFor(
    () =>
      findMessagePartsByType(hud, {
        text: "second",
        typeSelector: ".console-api",
        partSelector: ".message-body",
      }).length === 2
  );
  ok("Second page message appeared");
  is(
    findMessagePartsByType(hud, {
      text: "first",
      typeSelector: ".console-api",
      partSelector: ".message-body",
    }).length,
    0,
    "First page message disappeared"
  );

  info("Go back to the first page");
  gBrowser.selectedBrowser.goBack();
  // When going pack, the page isn't reloaded, so that we only get the pageshow event
  await waitFor(
    () =>
      findMessagePartsByType(hud, {
        text: "first document show",
        typeSelector: ".console-api",
        partSelector: ".message-body",
      }).length === 1
  );
  ok("First page message re-appeared");
  is(
    gBrowser.selectedBrowser.browsingContext.currentWindowGlobal.innerWindowId,
    firstPageInnerWindowId,
    "The first page is really a bfcache navigation, keeping the same WindowGlobal"
  );
  is(
    findMessagePartsByType(hud, {
      text: "second",
      typeSelector: ".console-api",
      partSelector: ".message-body",
    }).length,
    0,
    "Second page message disappeared"
  );

  info("Go forward to the original second page");
  gBrowser.selectedBrowser.goForward();
  await waitFor(
    () =>
      findMessagePartsByType(hud, {
        text: "second document show",
        typeSelector: ".console-api",
        partSelector: ".message-body",
      }).length === 1
  );
  ok("Second page message appeared");
  is(
    gBrowser.selectedBrowser.browsingContext.currentWindowGlobal.innerWindowId,
    secondPageInnerWindowId,
    "The second page is really a bfcache navigation, keeping the same WindowGlobal"
  );
  is(
    findMessagePartsByType(hud, {
      text: "first",
      typeSelector: ".console-api",
      partSelector: ".message-body",
    }).length,
    0,
    "First page message disappeared"
  );

  await closeToolbox();
});

add_task(async function () {
  info("Testing that messages persist on a refresh if logs are persisted");

  const hud = await openNewTabAndConsole(TEST_COM_URI);

  await toggleConsoleSetting(
    hud,
    ".webconsole-console-settings-menu-item-persistentLogs"
  );

  await logAndAssertInitialMessages(hud);

  const onNavigatedMessage = waitForMessageByType(
    hud,
    "Navigated to " + TEST_COM_URI,
    ".navigationMarker"
  );
  const onReloaded = hud.ui.once("reloaded");
  // Because will-navigate DOCUMENT_EVENT timestamp is shifted to workaround some other limitation,
  // the reported time of navigation may actually be slightly off and be older than the real navigation start
  let timeBeforeNavigation = Date.now() - WILL_NAVIGATE_TIME_SHIFT;
  reloadBrowser();
  await onNavigatedMessage;
  await onReloaded;

  ok(true, "Navigation message appeared as expected");
  is(
    findAllMessages(hud).length,
    INITIAL_LOGS_NUMBER + 1,
    "Messages logged before navigation are still visible"
  );

  assertLastMessageIsNavigationMessage(hud, timeBeforeNavigation, TEST_COM_URI);

  info(
    "Testing that messages also persist when doing a cross origin navigation if logs are persisted"
  );
  const onNavigatedMessage2 = waitForMessageByType(
    hud,
    "Navigated to " + TEST_ORG_URI,
    ".navigationMarker"
  );
  timeBeforeNavigation = Date.now() - WILL_NAVIGATE_TIME_SHIFT;
  await navigateTo(TEST_ORG_URI);
  await onNavigatedMessage2;

  ok(true, "Second navigation message appeared as expected");
  is(
    findAllMessages(hud).length,
    INITIAL_LOGS_NUMBER + 2,
    "Messages logged before the second navigation are still visible"
  );

  assertLastMessageIsNavigationMessage(hud, timeBeforeNavigation, TEST_ORG_URI);

  info(
    "Test doing a second cross origin navigation in order to triger a target switching with a target following the window global lifecycle"
  );
  const onNavigatedMessage3 = waitForMessageByType(
    hud,
    "Navigated to " + TEST_MOCHI_URI,
    ".navigationMarker"
  );
  timeBeforeNavigation = Date.now() - WILL_NAVIGATE_TIME_SHIFT;
  await navigateTo(TEST_MOCHI_URI);
  await onNavigatedMessage3;

  ok(true, "Third navigation message appeared as expected");
  is(
    findAllMessages(hud).length,
    INITIAL_LOGS_NUMBER + 3,
    "Messages logged before the third navigation are still visible"
  );

  assertLastMessageIsNavigationMessage(
    hud,
    timeBeforeNavigation,
    TEST_MOCHI_URI
  );

  await closeToolbox();
});

add_task(async function consoleClearPersist() {
  info("Testing that messages persist on console.clear if logs are persisted");

  await pushPref("devtools.webconsole.persistlog", true);
  const hud = await openNewTabAndConsole(TEST_COM_URI);

  await logAndAssertInitialMessages(hud);

  info("Send a console.clear() and another log from the content page");
  const onConsoleClearPrevented = waitForMessageByType(
    hud,
    "console.clear() was prevented",
    ".console-api"
  );
  SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
    content.wrappedJSObject.console.clear();
    content.wrappedJSObject.console.log("after clear");
  });

  await waitForMessageByType(hud, "after clear", ".log");
  await onConsoleClearPrevented;
  ok(true, "console.clear was handled by the client");

  Assert.strictEqual(
    findAllMessages(hud).length,
    INITIAL_LOGS_NUMBER + 2,
    "All initial messages are still displayed, with the 2 new ones"
  );

  await closeToolbox();
});

function assertLastMessageIsNavigationMessage(hud, timeBeforeNavigation, url) {
  const { visibleMessages, mutableMessagesById } = hud.ui.wrapper
    .getStore()
    .getState().messages;
  const lastMessageId = visibleMessages.at(-1);
  const lastMessage = mutableMessagesById.get(lastMessageId);

  is(
    lastMessage.type,
    MESSAGE_TYPE.NAVIGATION_MARKER,
    "The last message is a navigation marker"
  );
  is(
    lastMessage.messageText,
    "Navigated to " + url,
    "The navigation message is correct"
  );
  // It is surprising, but the navigation may be timestamped at the same exact time
  // as timeBeforeNavigation time record.
  Assert.greaterOrEqual(
    lastMessage.timeStamp,
    timeBeforeNavigation,
    "The navigation message has a timestamp newer (or equal) than the time before the navigation..."
  );
  Assert.less(
    lastMessage.timeStamp,
    Date.now(),
    "...and older than current time"
  );
}