summaryrefslogtreecommitdiffstats
path: root/devtools/client/shared/test/browser_dbg_listtabs-03.js
blob: 3306605707ebd68ff71ccbdd893a736813c64877 (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
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

/**
 * Assert the lifecycle of tab descriptors between listTabs and getTab
 */

var {
  DevToolsServer,
} = require("resource://devtools/server/devtools-server.js");
var {
  DevToolsClient,
} = require("resource://devtools/client/devtools-client.js");

const TAB1_URL = EXAMPLE_URL + "doc_empty-tab-01.html";

add_task(async function test() {
  // This test assert RDP APIs which were only meaningful when doing client side targets.
  // Now that targets are all created by the Watcher, it is no longer meaningful to cover this.
  // We should probably remove this test in bug 1721852.
  await pushPref("devtools.target-switching.server.enabled", false);

  DevToolsServer.init();
  DevToolsServer.registerAllActors();

  const transport = DevToolsServer.connectPipe();
  const client = new DevToolsClient(transport);
  const [type] = await client.connect();
  is(type, "browser", "Root actor should identify itself as a browser.");
  const tab1 = await addTab(TAB1_URL);

  await assertListTabs(tab1, client.mainRoot);

  const tab2 = await addTab(TAB1_URL);
  // To run last as it will close the client
  await assertGetTab(client, client.mainRoot, tab2);
});

async function assertListTabs(tab, rootFront) {
  const tabDescriptors = await rootFront.listTabs();
  is(tabDescriptors.length, 2, "Should be two tabs");

  const tabDescriptor = tabDescriptors.find(d => d.url == TAB1_URL);
  ok(tabDescriptor, "Should have a descriptor actor for the tab");
  ok(
    !tabDescriptor.isLocalTab,
    "listTabs's tab descriptor aren't considered as local tabs"
  );

  const tabTarget = await tabDescriptor.getTarget();
  ok(isTargetAttached(tabTarget), "The tab target should be attached");

  info("Detach the tab target");
  const onTargetDestroyed = tabTarget.once("target-destroyed");
  await tabTarget.detach();

  info("Wait for target destruction");
  await onTargetDestroyed;

  // When the target is detached and destroyed,
  // the descriptor stays alive, because the tab is still opened.
  // As we support top level target switching, the descriptor can be kept alive
  // when the target is destroyed.
  ok(
    !tabDescriptor.isDestroyed(),
    "The tab descriptor isn't destroyed on target detach"
  );

  info("Close the descriptor's tab");
  const onDescriptorDestroyed = tabDescriptor.once("descriptor-destroyed");
  await removeTab(tab);

  info("Wait for descriptor destruction");
  await onDescriptorDestroyed;

  ok(
    tabTarget.isDestroyed(),
    "The tab target should be destroyed after closing the tab"
  );
  ok(
    tabDescriptor.isDestroyed(),
    "The tab descriptor is also always destroyed after tab closing"
  );

  // Compared to getTab, the client should be kept alive.
  // Do another request to assert that.
  await rootFront.listTabs();
}

async function assertGetTab(client, rootFront, tab) {
  const tabDescriptor = await rootFront.getTab({ tab });
  ok(tabDescriptor, "Should have a descriptor actor for the tab");
  ok(
    tabDescriptor.isLocalTab,
    "getTab's tab descriptor are considered as local tabs, but only when a tab argument is given"
  );

  // Also assert that getTab only return local tabs when passing the "tab" argument.
  // Other arguments will return a non-local tab, having same behavior as listTabs's descriptors
  // Test on another tab, otherwise we would return the same descriptor as the one retrieved
  // from assertGetTab.
  const tab2 = await addTab("data:text/html,second tab");
  const tabDescriptor2 = await rootFront.getTab({
    browserId: tab2.linkedBrowser.browserId,
  });
  ok(
    !tabDescriptor2.isLocalTab,
    "getTab's tab descriptor aren't considered as local tabs when we pass an browserId"
  );
  await removeTab(tab2);

  const tabTarget = await tabDescriptor.getTarget();
  ok(isTargetAttached(tabTarget), "The tab target should be attached");

  info("Detach the tab target");
  const onTargetDestroyed = tabTarget.once("target-destroyed");
  await tabTarget.detach();

  info("Wait for target destruction");
  await onTargetDestroyed;

  // When the target is detached and destroyed,
  // the descriptor stays alive, because the tab is still opened.
  // And compared to listTabs, getTab's descriptor are considered local tabs.
  // As we support top level target switching, the descriptor can be kept alive
  // when the target is destroyed.
  ok(
    !tabDescriptor.isDestroyed(),
    "The tab descriptor isn't destroyed on target detach"
  );

  info("Close the descriptor's tab");
  const onDescriptorDestroyed = tabDescriptor.once("descriptor-destroyed");
  await removeTab(tab);

  info("Wait for descriptor destruction");
  await onDescriptorDestroyed;

  ok(
    tabTarget.isDestroyed(),
    "The tab target should be destroyed after closing the tab"
  );
  ok(
    tabDescriptor.isDestroyed(),
    "The tab descriptor is also always destroyed after tab closing"
  );

  await client.close();
}

function isTargetAttached(targetFront) {
  return !!targetFront?.targetForm?.threadActor;
}