topological-nodered-wdio 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,102 @@
1
+ const common = require('./wdio-common')
2
+
3
+ module.exports = function(RED) {
4
+ function newSession(config) {
5
+ RED.nodes.createNode(this, config)
6
+ const node = this
7
+
8
+ common.clearStatus(node)
9
+
10
+ node.on('input', async (msg) => {
11
+ try {
12
+ const webdriverConfig = Object.assign(
13
+ { logLevel: config.logLevel },
14
+ parseUri(config.webdriverUri || msg.webdriverUri, node),
15
+ getCapabilities(
16
+ config.webdriverProvider,
17
+ config.webdriverBrowser || msg.webdriverBrowser,
18
+ config.browserlessToken
19
+ )
20
+ )
21
+ node.log = `Open new browser.`
22
+ let b = await common.newSession(webdriverConfig, node, node.context())
23
+ await common.log(node)
24
+ common.connectedStatus(node)
25
+ msg.payload = b.sessionId
26
+ node.send(msg)
27
+ } catch (e) {
28
+ common.handleError(e, node, msg)
29
+ }
30
+ })
31
+
32
+ node.on('close', async (done) => {
33
+ try {
34
+ if (config.killSession) {
35
+ let b = await common.deleteSession(node.context())
36
+ let sessionId = ''
37
+ if (b && b.sessionId) sessionId = b.sessionId
38
+ common.disconnectedStatus(node)
39
+ node.log('Disconnected webdriver session ' + sessionId)
40
+ }
41
+ } catch (e) {
42
+ common.handleError(e, node, msg)
43
+ }
44
+ done()
45
+ })
46
+ }
47
+ RED.nodes.registerType('new-session', newSession)
48
+ }
49
+
50
+ const parseUri = (uri, node) => {
51
+ let uriComponents
52
+ try {
53
+ if (uri[uri.length - 1] !== '/') uri += '/'
54
+ let parsed = uri.match(/(\w+):\/\/(.+):(\d+)(\/.*)/)
55
+ uriComponents = {
56
+ protocol: parsed[1],
57
+ hostname: parsed[2],
58
+ port: parseInt(parsed[3]),
59
+ path: parsed[4]
60
+ }
61
+ } catch (e) {
62
+ common.handleError(
63
+ new Error(
64
+ 'Invalid URI, expected format "<protocol>://<host>:<port>/<path>'
65
+ ),
66
+ node
67
+ )
68
+ }
69
+
70
+ return uriComponents
71
+ }
72
+
73
+ const getCapabilities = (vendor, browser) => {
74
+ let capabilities
75
+
76
+ if (vendor === 'browserless.io') {
77
+ capabilities = {
78
+ browserName: browser,
79
+ 'goog:chromeOptions': {
80
+ args: ['--headless', '--no-sandbox']
81
+ }
82
+ }
83
+ } else if (vendor === 'local' && browser === 'chromium') {
84
+ capabilities = {
85
+ browserName: 'chrome',
86
+ 'goog:chromeOptions': {
87
+ args: ['--headless', '--no-sandbox'],
88
+ w3c: false
89
+ }
90
+ }
91
+ } else if (vendor === 'local') {
92
+ capabilities = {
93
+ browserName: browser,
94
+ //platformName: 'Linux',
95
+ 'goog:chromeOptions': {
96
+ w3c: false
97
+ }
98
+ }
99
+ }
100
+
101
+ return { capabilities }
102
+ }
@@ -0,0 +1,151 @@
1
+ const wdio = require('webdriverio')
2
+ let newSessionNode
3
+
4
+ module.exports.getBrowser = (context) => {
5
+ let browser = context.flow.get('wdio_browser')
6
+ if (!browser || !browser.sessionId)
7
+ throw new Error('No session defined - call newSession first')
8
+
9
+ return browser
10
+ }
11
+
12
+ /*
13
+ config = {
14
+ logLevel: 'error',
15
+ protocol: 'https',
16
+ hostname: '<key>@chrome.browserless.io',
17
+ port: 443,
18
+ path: '/webdriver',
19
+ capabilities: {
20
+ browserName: 'chrome',
21
+ chromeOptions: {
22
+ args: ['--headless', '--no-sandbox']
23
+ }
24
+ }
25
+ }
26
+ */
27
+ module.exports.newSession = async (config, node, context) => {
28
+ let browser
29
+ try {
30
+ browser = await wdio.remote(config)
31
+ context.flow.set('wdio_browser', browser)
32
+ newSessionNode = node
33
+ } catch (e) {
34
+ throw e
35
+ }
36
+ return browser
37
+ }
38
+
39
+ module.exports.deleteSession = async (context) => {
40
+ let b
41
+ let browser = context.flow.get('wdio_browser')
42
+ try {
43
+ b = { sessionId: browser.sessionId }
44
+ await browser.closeWindow()
45
+ await browser.deleteSession()
46
+ context.flow.set('wdio_browser', null)
47
+ if (newSessionNode) module.exports.disconnected(newSessionNode)
48
+ } catch (e) {}
49
+ return b
50
+ }
51
+
52
+ module.exports.getElementId = async (browser, using, value) => {
53
+ let elementId
54
+ try {
55
+ const element = await browser.findElement(using, value)
56
+ if (element && Object.keys(element)) {
57
+ elementId = element[Object.keys(element)[0]]
58
+ } else {
59
+ let e
60
+ if (element && element.message) {
61
+ e = element.message
62
+ } else {
63
+ e = 'Element not found'
64
+ }
65
+ throw new Error(e)
66
+ }
67
+ } catch (e) {
68
+ throw e
69
+ }
70
+ return elementId
71
+ }
72
+
73
+ module.exports.getElement = async (browser, using, value) => {
74
+ let selector = ''
75
+ let element
76
+ switch (using) {
77
+ case 'id':
78
+ selector = '#' + value
79
+ break
80
+ case 'name':
81
+ selector = value
82
+ break
83
+ case 'className':
84
+ selector = '.' + value
85
+ break
86
+ case 'selector':
87
+ selector = value
88
+ break
89
+ default:
90
+ selector = value
91
+ break
92
+ }
93
+
94
+ try {
95
+ element = await browser.$(selector)
96
+ } catch (e) {
97
+ throw e
98
+ }
99
+
100
+ return element
101
+ }
102
+
103
+ module.exports.handleError = (e, node, msg) => {
104
+ console.log(e)
105
+ module.exports.errorStatus(node)
106
+ node.error(e, msg)
107
+ }
108
+
109
+ module.exports.clearStatus = (node) => {
110
+ node.status({})
111
+ }
112
+
113
+ module.exports.connectedStatus = (node) => {
114
+ node.status({
115
+ fill: 'green',
116
+ shape: 'dot',
117
+ text: 'connected'
118
+ })
119
+ }
120
+
121
+ module.exports.disconnectedStatus = (node) => {
122
+ node.status({
123
+ fill: 'green',
124
+ shape: 'ring',
125
+ text: 'disconnected'
126
+ })
127
+ }
128
+
129
+ module.exports.successStatus = (node) => {
130
+ node.status({
131
+ fill: 'green',
132
+ shape: 'ring',
133
+ text: 'done'
134
+ })
135
+ }
136
+
137
+ module.exports.errorStatus = (node) => {
138
+ node.status({
139
+ fill: 'red',
140
+ shape: 'ring',
141
+ text: 'error'
142
+ })
143
+ }
144
+
145
+ module.exports.log = async (node) => {
146
+ let context = node.context()
147
+ let stepCount = await (context.global.get('stepCount') || 0) + 1
148
+ let document = await context.global.get('document') || ''
149
+ await context.global.set('document', `${document}\n${stepCount}. Node: ${node.name} - \t${node.log}`)
150
+ await context.global.set('stepCount', stepCount)
151
+ }
@@ -0,0 +1,91 @@
1
+ <script type="text/javascript">
2
+ function setWindowAction() {
3
+ let action = $('#node-input-action').val()
4
+ $('#actionValue').hide()
5
+ $('#actionIndex').hide()
6
+ if (action === 'byName' || action === 'open') {
7
+ $('#actionValue').show()
8
+ }
9
+ if (action == 'byIndex') {
10
+ $('#actionIndex').show()
11
+ }
12
+ }
13
+
14
+ RED.nodes.registerType('window-action', {
15
+ category: 'Webdriver IO',
16
+ color: '#a6bbcf',
17
+ defaults: {
18
+ name: { value: '' },
19
+ action: { value: 'byName' },
20
+ value: { value: '' },
21
+ index: { value: '' }
22
+ },
23
+ inputs: 1,
24
+ outputs: 1,
25
+ icon: 'white-globe.png',
26
+ label: function() {
27
+ return this.name || 'window action'
28
+ },
29
+ oneditprepare: function() {
30
+ setWindowAction()
31
+ }
32
+ })
33
+ </script>
34
+
35
+ <script type="text/x-red" data-template-name="window-action">
36
+ <div class="form-row">
37
+ <label for="node-input-action"><i class="fa fa-tasks"></i> Action</label>
38
+ <select type="text" id="node-input-action" style="width:70%;" onchange="setWindowAction()">
39
+ <option value="byName">Switch to Window by Name</option>
40
+ <option value="byIndex">Switch to Window by Index</option>
41
+ <option value="getHandle">Get Window handle</option>
42
+ <option value="close">Close Window</option>
43
+ <option value="open">Open Window</option>
44
+ </select>
45
+ </div>
46
+ <div class="form-row" id="actionValue">
47
+ <label for="node-input-value"><i class="fa fa-tasks"></i> Window Name</label>
48
+ <input id="node-input-value" type="text" placeholder="URL or Title of window">
49
+ </div>
50
+ <div class="form-row" id="actionIndex">
51
+ <label for="node-input-index"><i class="fa fa-tasks"></i> Index</label>
52
+ <input id="node-input-index" type="text" placeholder="starts 0">
53
+ </div>
54
+ <div class="form-row">
55
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
56
+ <input id="node-input-name" type="text">
57
+ </div>
58
+ </script>
59
+
60
+ <script type="text/x-red" data-help-name="window-action">
61
+ <h3>Selected action of the node performs on browser windows.</h3>
62
+
63
+ <h3>Inputs</h3>
64
+ <dl class="message-properties">
65
+ <dt><code>msg.value</code>: <span class="property-type">string</span></dt>
66
+ <dd>URL or Title the window to target</dd>
67
+ <dt><code>msg.index</code><span class="property-type">string</span></dt>
68
+ <dd>zero-based index to target the desired window<br></dd>
69
+ </dl>
70
+ <h3>Details</h3>
71
+ <dl class="message-properties">
72
+ <dt>Action: <span class="property-type">Select</span></dt>
73
+ <dd>
74
+ <ul>
75
+ <li><b>Switch to Window by Name</b></li>
76
+ <ul>
77
+ <li>Use URL or Title to switch to the browser tab/window.</li>
78
+ </ul>
79
+ <li><b>Switch to Window by Index</b></li>
80
+ <ul>
81
+ <li>Use a zero-based index to target the browser tab/window</li>
82
+ </ul>
83
+ <li><b>Get window Handle</b></li>
84
+ <li><b>Close Window</b></li>
85
+ <li><b>Open Window</b></li>
86
+ </ul>
87
+ </dd>
88
+ </dl>
89
+
90
+ </script>
91
+
@@ -0,0 +1,42 @@
1
+ const common = require('./wdio-common')
2
+
3
+ module.exports = function(RED) {
4
+ function windowAction(config) {
5
+ RED.nodes.createNode(this, config)
6
+ const node = this
7
+ common.clearStatus(node)
8
+
9
+ node.on('input', async (msg) => {
10
+ try {
11
+ let browser = await common.getBrowser(node.context())
12
+
13
+ let value = config.value || msg.value
14
+ let index = config.index || msg.index
15
+
16
+ if (config.action === 'byName') {
17
+ node.log = `Switch to the browser window with window title: "${value}".`
18
+ await browser.switchWindow(value)
19
+ } else if (config.action === 'byIndex') {
20
+ node.log = `Switch to the browser window with window index: "${index}".`
21
+ let handles = await browser.getWindowHandles()
22
+ await browser.switchWindow(handles[index])
23
+ } else if (config.action === 'getHandle') {
24
+ node.log = `Get all the browser windows.`
25
+ msg.payload = await browser.getWindowHandles()
26
+ } else if (config.action === 'close') {
27
+ node.log = `Close the active browser window.`
28
+ await browser.closeWindow()
29
+ } else if (config.action === 'open') {
30
+ node.log = `Open a new window with url: "${value}".`
31
+ await browser.createWindow(value)
32
+ }
33
+ await common.log(node)
34
+ common.successStatus(node)
35
+ node.send(msg)
36
+ } catch (e) {
37
+ common.handleError(e, node, msg)
38
+ }
39
+ })
40
+ }
41
+ RED.nodes.registerType('window-action', windowAction)
42
+ }