@applitools/eyes-cypress 3.28.0 → 3.28.2

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/bin/eyes-setup.js +21 -21
  3. package/dist/browser/spec-driver.js +2 -5
  4. package/index.d.ts +7 -6
  5. package/index.js +2 -2
  6. package/package.json +13 -11
  7. package/src/browser/commands.js +79 -84
  8. package/src/browser/eyesCheckMapping.js +77 -71
  9. package/src/browser/eyesOpenMapping.js +28 -32
  10. package/src/browser/makeSend.js +5 -10
  11. package/src/browser/refer.js +28 -28
  12. package/src/browser/sendRequest.js +6 -6
  13. package/src/browser/socket.js +72 -73
  14. package/src/browser/socketCommands.js +34 -45
  15. package/src/browser/spec-driver.ts +33 -41
  16. package/src/plugin/concurrencyMsg.js +4 -4
  17. package/src/plugin/config.js +16 -17
  18. package/src/plugin/configParams.js +3 -3
  19. package/src/plugin/defaultPort.js +1 -1
  20. package/src/plugin/errorDigest.js +27 -35
  21. package/src/plugin/getErrorsAndDiffs.js +11 -11
  22. package/src/plugin/handleTestResults.js +16 -19
  23. package/src/plugin/hooks.js +12 -12
  24. package/src/plugin/isGlobalHooksSupported.js +6 -7
  25. package/src/plugin/pluginExport.js +38 -43
  26. package/src/plugin/server.js +50 -53
  27. package/src/plugin/startPlugin.js +9 -9
  28. package/src/plugin/webSocket.js +63 -64
  29. package/src/setup/addEyesCommands.js +12 -12
  30. package/src/setup/addEyesCypressPlugin.js +6 -6
  31. package/src/setup/getCypressPaths.js +28 -32
  32. package/src/setup/getCypressVersion.js +7 -9
  33. package/src/setup/getFilePath.js +8 -8
  34. package/src/setup/handleCommands.js +11 -11
  35. package/src/setup/handlePlugin.js +10 -10
  36. package/src/setup/handleTypeScript.js +8 -8
  37. package/src/setup/isCommandsDefined.js +3 -3
  38. package/src/setup/isPluginDefined.js +3 -3
@@ -1,107 +1,107 @@
1
- const WebSocket = require('ws');
2
- const {v4: uuid} = require('uuid');
1
+ const WebSocket = require('ws')
2
+ const {v4: uuid} = require('uuid')
3
3
 
4
4
  function connectSocket(url) {
5
- const socket = new WebSocket(url);
6
- let passthroughListener;
7
- const listeners = new Map();
8
- const queue = new Set();
9
- let isReady = false;
5
+ const socket = new WebSocket(url)
6
+ let passthroughListener
7
+ const listeners = new Map()
8
+ const queue = new Set()
9
+ let isReady = false
10
10
 
11
- attach();
11
+ attach()
12
12
 
13
13
  function attach() {
14
- if (socket.readyState === WebSocket.CONNECTING) socket.on('open', () => attach(socket));
14
+ if (socket.readyState === WebSocket.CONNECTING) socket.on('open', () => attach(socket))
15
15
  else if (socket.readyState === WebSocket.OPEN) {
16
- isReady = true;
17
- queue.forEach(command => command());
18
- queue.clear();
16
+ isReady = true
17
+ queue.forEach(command => command())
18
+ queue.clear()
19
19
 
20
20
  socket.on('message', message => {
21
- const {name, key, payload} = deserialize(message);
22
- const fns = listeners.get(name);
23
- const keyListeners = key && listeners.get(`${name}/${key}`);
24
- if (fns) fns.forEach(fn => fn(payload, key));
25
- if (keyListeners) keyListeners.forEach(fn => fn(payload, key));
21
+ const {name, key, payload} = deserialize(message)
22
+ const fns = listeners.get(name)
23
+ const keyListeners = key && listeners.get(`${name}/${key}`)
24
+ if (fns) fns.forEach(fn => fn(payload, key))
25
+ if (keyListeners) keyListeners.forEach(fn => fn(payload, key))
26
26
 
27
27
  if (!fns && !keyListeners && passthroughListener) {
28
- passthroughListener(message);
28
+ passthroughListener(message)
29
29
  }
30
- });
30
+ })
31
31
  }
32
32
  }
33
33
 
34
34
  function disconnect() {
35
- if (!socket) return;
36
- socket.terminate();
37
- isReady = false;
38
- passthroughListener = null;
39
- queue.clear();
35
+ if (!socket) return
36
+ socket.terminate()
37
+ isReady = false
38
+ passthroughListener = null
39
+ queue.clear()
40
40
  }
41
41
 
42
42
  function setPassthroughListener(fn) {
43
- passthroughListener = fn;
43
+ passthroughListener = fn
44
44
  }
45
45
 
46
46
  function send(message) {
47
- const command = () => socket.send(message);
48
- if (isReady) command();
49
- else queue.add(command);
50
- return () => queue.delete(command);
47
+ const command = () => socket.send(message)
48
+ if (isReady) command()
49
+ else queue.add(command)
50
+ return () => queue.delete(command)
51
51
  }
52
52
 
53
53
  function on(type, fn) {
54
- const name = typeof type === 'string' ? type : `${type.name}/${type.key}`;
55
- let fns = listeners.get(name);
54
+ const name = typeof type === 'string' ? type : `${type.name}/${type.key}`
55
+ let fns = listeners.get(name)
56
56
  if (!fns) {
57
- fns = new Set();
58
- listeners.set(name, fns);
57
+ fns = new Set()
58
+ listeners.set(name, fns)
59
59
  }
60
- fns.add(fn);
61
- return () => off(name, fn);
60
+ fns.add(fn)
61
+ return () => off(name, fn)
62
62
  }
63
63
 
64
64
  function once(type, fn) {
65
- const off = on(type, (...args) => (fn(...args), off()));
66
- return off;
65
+ const off = on(type, (...args) => (fn(...args), off()))
66
+ return off
67
67
  }
68
68
 
69
69
  function off(name, fn) {
70
- if (!fn) return listeners.delete(name);
71
- const fns = listeners.get(name);
72
- if (!fns) return false;
73
- const existed = fns.delete(fn);
74
- if (!fns.size) listeners.delete(name);
75
- return existed;
70
+ if (!fn) return listeners.delete(name)
71
+ const fns = listeners.get(name)
72
+ if (!fns) return false
73
+ const existed = fns.delete(fn)
74
+ if (!fns.size) listeners.delete(name)
75
+ return existed
76
76
  }
77
77
 
78
78
  function emit(type, payload) {
79
- return send(serialize(type, payload));
79
+ return send(serialize(type, payload))
80
80
  }
81
81
 
82
82
  function request(name, payload) {
83
83
  return new Promise((resolve, reject) => {
84
- const key = uuid();
85
- emit({name, key}, payload);
84
+ const key = uuid()
85
+ emit({name, key}, payload)
86
86
  once({name, key}, response => {
87
- if (response.error) return reject(response.error);
88
- return resolve(response.result);
89
- });
90
- });
87
+ if (response.error) return reject(response.error)
88
+ return resolve(response.result)
89
+ })
90
+ })
91
91
  }
92
92
 
93
93
  function ref() {
94
- const command = () => socket._socket.ref();
95
- if (isReady) command();
96
- else queue.add(command);
97
- return () => queue.delete(command);
94
+ const command = () => socket._socket.ref()
95
+ if (isReady) command()
96
+ else queue.add(command)
97
+ return () => queue.delete(command)
98
98
  }
99
99
 
100
100
  function unref() {
101
- const command = () => socket._socket.unref();
102
- if (isReady) command();
103
- else queue.add(command);
104
- return () => queue.delete(command);
101
+ const command = () => socket._socket.unref()
102
+ if (isReady) command()
103
+ else queue.add(command)
104
+ return () => queue.delete(command)
105
105
  }
106
106
 
107
107
  return {
@@ -114,17 +114,16 @@ function connectSocket(url) {
114
114
  disconnect,
115
115
  ref,
116
116
  unref,
117
- };
117
+ }
118
118
  }
119
119
 
120
120
  function serialize(type, payload) {
121
- const message =
122
- typeof type === 'string' ? {name: type, payload} : {name: type.name, key: type.key, payload};
123
- return JSON.stringify(message);
121
+ const message = typeof type === 'string' ? {name: type, payload} : {name: type.name, key: type.key, payload}
122
+ return JSON.stringify(message)
124
123
  }
125
124
 
126
125
  function deserialize(message) {
127
- return JSON.parse(message);
126
+ return JSON.parse(message)
128
127
  }
129
128
 
130
- module.exports = connectSocket;
129
+ module.exports = connectSocket
@@ -1,24 +1,24 @@
1
- 'use strict';
1
+ 'use strict'
2
2
 
3
- const commandsImport = `\nimport '@applitools/eyes-cypress/commands'\n`;
4
- const oldName = `eyes.cypress`;
3
+ const commandsImport = `\nimport '@applitools/eyes-cypress/commands'\n`
4
+ const oldName = `eyes.cypress`
5
5
 
6
6
  function shouldSkipLine(line) {
7
- return line && (line.trim() === '' || /^\s*['"]use strict/.test(line) || /^\s*\/\//.test(line));
7
+ return line && (line.trim() === '' || /^\s*['"]use strict/.test(line) || /^\s*\/\//.test(line))
8
8
  }
9
9
 
10
10
  function addEyesCommands(content) {
11
11
  if (content.includes(oldName)) {
12
- return content.replace(oldName, 'eyes-cypress');
12
+ return content.replace(oldName, 'eyes-cypress')
13
13
  }
14
- const lines = content.split('\n');
15
- let i = 0;
14
+ const lines = content.split('\n')
15
+ let i = 0
16
16
  while (shouldSkipLine(lines[i++])) {}
17
- let index = i === 1 ? i : i - 1;
18
- lines.splice(index, 0, commandsImport);
17
+ let index = i === 1 ? i : i - 1
18
+ lines.splice(index, 0, commandsImport)
19
19
 
20
- return lines.join('\n');
20
+ return lines.join('\n')
21
21
  }
22
22
 
23
- module.exports = addEyesCommands;
24
- module.exports.commandsImport = commandsImport;
23
+ module.exports = addEyesCommands
24
+ module.exports.commandsImport = commandsImport
@@ -1,14 +1,14 @@
1
- 'use strict';
1
+ 'use strict'
2
2
 
3
- const pluginRequire = `\n\nrequire('@applitools/eyes-cypress')(module);\n`;
4
- const oldName = `eyes.cypress`;
3
+ const pluginRequire = `\n\nrequire('@applitools/eyes-cypress')(module);\n`
4
+ const oldName = `eyes.cypress`
5
5
 
6
6
  function addEyesCypressPlugin(content) {
7
7
  if (!content.includes(oldName)) {
8
- return content.replace(/([\s\S])$/, `$1${pluginRequire}`);
8
+ return content.replace(/([\s\S])$/, `$1${pluginRequire}`)
9
9
  } else {
10
- return content.replace(oldName, 'eyes-cypress');
10
+ return content.replace(oldName, 'eyes-cypress')
11
11
  }
12
12
  }
13
13
 
14
- module.exports = {addEyesCypressPlugin, pluginRequire};
14
+ module.exports = {addEyesCypressPlugin, pluginRequire}
@@ -1,13 +1,13 @@
1
- 'use strict';
1
+ 'use strict'
2
2
 
3
- const fs = require('fs');
4
- const path = require('path');
3
+ const fs = require('fs')
4
+ const path = require('path')
5
5
 
6
6
  function getCypressPaths({cwd, isCypress10}) {
7
7
  if (isCypress10) {
8
- return getCypressPaths10AndAbove(cwd);
8
+ return getCypressPaths10AndAbove(cwd)
9
9
  } else {
10
- return getCypressPaths9AndBelow(cwd);
10
+ return getCypressPaths9AndBelow(cwd)
11
11
  }
12
12
  }
13
13
 
@@ -16,70 +16,66 @@ function getCypressPaths10AndAbove(cwd) {
16
16
  ? path.resolve(cwd, 'cypress.config.js')
17
17
  : fs.existsSync(path.resolve(cwd, 'cypress.config.ts'))
18
18
  ? path.resolve(cwd, 'cypress.config.ts')
19
- : undefined;
19
+ : undefined
20
20
 
21
21
  if (cypressConfigPath) {
22
- const configContent = fs.readFileSync(cypressConfigPath, 'utf-8');
23
- const supportFilePath = getSupportFilePathFromCypress10Config({cwd, configContent});
24
- const typeScriptFilePath = supportFilePath
25
- ? path.resolve(path.dirname(supportFilePath), 'index.d.ts')
26
- : undefined;
22
+ const configContent = fs.readFileSync(cypressConfigPath, 'utf-8')
23
+ const supportFilePath = getSupportFilePathFromCypress10Config({cwd, configContent})
24
+ const typeScriptFilePath = supportFilePath ? path.resolve(path.dirname(supportFilePath), 'index.d.ts') : undefined
27
25
  return {
28
26
  config: cypressConfigPath,
29
27
  plugin: cypressConfigPath,
30
28
  support: supportFilePath,
31
29
  typescript: typeScriptFilePath,
32
- };
30
+ }
33
31
  } else {
34
32
  throw new Error(
35
33
  `No configuration file found at ${cwd}. This is usually caused by setting up Eyes before setting up Cypress. Please run "npx cypress open" first.`,
36
- );
34
+ )
37
35
  }
38
36
  }
39
37
 
40
38
  function getSupportFilePathFromCypress10Config({cwd, configContent}) {
41
- let supportFilePath;
39
+ let supportFilePath
42
40
  if (configContent.includes('supportFile')) {
43
- const regex = new RegExp(/(?:supportFile:)(?:\s*)(.*)/g);
44
- const filePath = regex.exec(configContent)[1].replace(/['|"|,]*/g, '');
45
- supportFilePath = path.resolve(cwd, filePath);
41
+ const regex = new RegExp(/(?:supportFile:)(?:\s*)(.*)/g)
42
+ const filePath = regex.exec(configContent)[1].replace(/['|"|,]*/g, '')
43
+ supportFilePath = path.resolve(cwd, filePath)
46
44
  } else {
47
45
  if (fs.existsSync(path.resolve(cwd, 'cypress/support/e2e.js'))) {
48
- supportFilePath = path.resolve(cwd, 'cypress/support/e2e.js');
46
+ supportFilePath = path.resolve(cwd, 'cypress/support/e2e.js')
49
47
  } else if (fs.existsSync(path.resolve(cwd, 'cypress/support/e2e.ts'))) {
50
- supportFilePath = path.resolve(cwd, 'cypress/support/e2e.ts');
48
+ supportFilePath = path.resolve(cwd, 'cypress/support/e2e.ts')
51
49
  } else if (fs.existsSync(path.resolve(cwd, 'cypress/support/component.js'))) {
52
- supportFilePath = path.resolve(cwd, 'cypress/support/component.js');
50
+ supportFilePath = path.resolve(cwd, 'cypress/support/component.js')
53
51
  } else if (fs.existsSync(path.resolve(cwd, 'cypress/support/component.ts'))) {
54
- supportFilePath = path.resolve(cwd, 'cypress/support/component.ts');
52
+ supportFilePath = path.resolve(cwd, 'cypress/support/component.ts')
55
53
  }
56
54
  }
57
- return supportFilePath;
55
+ return supportFilePath
58
56
  }
59
57
 
60
58
  function getCypressPaths9AndBelow(cwd) {
61
- const cypressConfigPath = path.resolve(cwd, 'cypress.json');
59
+ const cypressConfigPath = path.resolve(cwd, 'cypress.json')
62
60
  if (fs.existsSync(cypressConfigPath)) {
63
61
  try {
64
- const configContent = JSON.parse(fs.readFileSync(cypressConfigPath));
65
- const supportFilePath = path.resolve(configContent.supportFile || 'cypress/support/index.js');
66
- const typeScriptFilePath = supportFilePath
67
- ? path.resolve(path.dirname(supportFilePath), 'index.d.ts')
68
- : undefined;
62
+ const configContent = JSON.parse(fs.readFileSync(cypressConfigPath))
63
+ const supportFilePath = path.resolve(configContent.supportFile || 'cypress/support/index.js')
64
+ const typeScriptFilePath = supportFilePath ? path.resolve(path.dirname(supportFilePath), 'index.d.ts') : undefined
69
65
  return {
70
66
  config: cypressConfigPath,
71
67
  plugin: path.resolve(cwd, configContent.pluginsFile || 'cypress/plugins/index.js'),
72
68
  support: supportFilePath,
73
69
  typescript: typeScriptFilePath,
74
- };
70
+ }
75
71
  } catch (err) {
76
- throw new Error(`cypress.json at ${cypressConfigPath} is not a valid JSON: ${err.message}`);
72
+ throw new Error(`cypress.json at ${cypressConfigPath} is not a valid JSON: ${err.message}`)
77
73
  }
78
74
  } else {
79
75
  throw new Error(
80
76
  `No configuration file found at ${cypressConfigPath}. This is usually caused by setting up Eyes before setting up Cypress. Please run "npx cypress open" first.`,
81
- );
77
+ )
82
78
  }
83
79
  }
84
80
 
85
- module.exports = getCypressPaths;
81
+ module.exports = getCypressPaths
@@ -1,13 +1,11 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const cwd = process.cwd();
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+ const cwd = process.cwd()
4
4
 
5
5
  function getCypressVersion() {
6
- const cypressPackage = require.resolve('cypress', {paths: [cwd]});
7
- const packageJson = JSON.parse(
8
- fs.readFileSync(path.resolve(path.dirname(cypressPackage), 'package.json')),
9
- );
10
- return packageJson.version;
6
+ const cypressPackage = require.resolve('cypress', {paths: [cwd]})
7
+ const packageJson = JSON.parse(fs.readFileSync(path.resolve(path.dirname(cypressPackage), 'package.json')))
8
+ return packageJson.version
11
9
  }
12
10
 
13
- module.exports = getCypressVersion;
11
+ module.exports = getCypressVersion
@@ -1,22 +1,22 @@
1
- 'use strict';
1
+ 'use strict'
2
2
 
3
- const {resolve, join, dirname} = require('path');
3
+ const {resolve, join, dirname} = require('path')
4
4
 
5
5
  function getFilePath(type, cypressConfig, cwd) {
6
6
  let filePath = {
7
7
  plugins: join('cypress', 'plugins', 'index.js'),
8
8
  support: join('cypress', 'support', 'index.js'),
9
9
  typeScript: join('cypress', 'support', 'index.d.ts'),
10
- }[type];
10
+ }[type]
11
11
 
12
12
  if (type === 'typeScript' && cypressConfig && cypressConfig[`supportFile`]) {
13
- const supportDir = dirname(cypressConfig[`supportFile`]);
14
- filePath = resolve(supportDir, 'index.d.ts');
13
+ const supportDir = dirname(cypressConfig[`supportFile`])
14
+ filePath = resolve(supportDir, 'index.d.ts')
15
15
  }
16
16
 
17
- filePath = (cypressConfig && cypressConfig[`${type}File`]) || filePath;
17
+ filePath = (cypressConfig && cypressConfig[`${type}File`]) || filePath
18
18
 
19
- return resolve(cwd, filePath);
19
+ return resolve(cwd, filePath)
20
20
  }
21
21
 
22
- module.exports = getFilePath;
22
+ module.exports = getFilePath
@@ -1,23 +1,23 @@
1
- 'use strict';
1
+ 'use strict'
2
2
 
3
- const fs = require('fs');
4
- const chalk = require('chalk');
5
- const addEyesCommands = require('./addEyesCommands');
6
- const isCommandsDefined = require('./isCommandsDefined');
3
+ const fs = require('fs')
4
+ const chalk = require('chalk')
5
+ const addEyesCommands = require('./addEyesCommands')
6
+ const isCommandsDefined = require('./isCommandsDefined')
7
7
 
8
8
  function handleCommands(supportFilePath) {
9
9
  if (supportFilePath) {
10
- const supportFileContent = fs.readFileSync(supportFilePath, 'utf-8');
10
+ const supportFileContent = fs.readFileSync(supportFilePath, 'utf-8')
11
11
 
12
12
  if (!isCommandsDefined(supportFileContent)) {
13
- fs.writeFileSync(supportFilePath, addEyesCommands(supportFileContent));
14
- console.log(chalk.cyan('Commands defined.'));
13
+ fs.writeFileSync(supportFilePath, addEyesCommands(supportFileContent))
14
+ console.log(chalk.cyan('Commands defined.'))
15
15
  } else {
16
- console.log(chalk.cyan('Commands already defined.'));
16
+ console.log(chalk.cyan('Commands already defined.'))
17
17
  }
18
18
  } else {
19
- throw new Error('Commands could not be defined. Support file could not be found');
19
+ throw new Error('Commands could not be defined. Support file could not be found')
20
20
  }
21
21
  }
22
22
 
23
- module.exports = handleCommands;
23
+ module.exports = handleCommands
@@ -1,19 +1,19 @@
1
- 'use strict';
1
+ 'use strict'
2
2
 
3
- const chalk = require('chalk');
4
- const {addEyesCypressPlugin} = require('./addEyesCypressPlugin');
5
- const isPluginDefined = require('./isPluginDefined');
6
- const fs = require('fs');
3
+ const chalk = require('chalk')
4
+ const {addEyesCypressPlugin} = require('./addEyesCypressPlugin')
5
+ const isPluginDefined = require('./isPluginDefined')
6
+ const fs = require('fs')
7
7
 
8
8
  function handlePlugin(pluginsFilePath) {
9
- const fileContent = fs.readFileSync(pluginsFilePath, 'utf-8');
9
+ const fileContent = fs.readFileSync(pluginsFilePath, 'utf-8')
10
10
 
11
11
  if (!isPluginDefined(fileContent)) {
12
- fs.writeFileSync(pluginsFilePath, addEyesCypressPlugin(fileContent));
13
- console.log(chalk.cyan('Plugins defined.'));
12
+ fs.writeFileSync(pluginsFilePath, addEyesCypressPlugin(fileContent))
13
+ console.log(chalk.cyan('Plugins defined.'))
14
14
  } else {
15
- console.log(chalk.cyan('Plugins already defined'));
15
+ console.log(chalk.cyan('Plugins already defined'))
16
16
  }
17
17
  }
18
18
 
19
- module.exports = handlePlugin;
19
+ module.exports = handlePlugin
@@ -1,15 +1,15 @@
1
- 'use strict';
2
- const chalk = require('chalk');
3
- const {writeFileSync, existsSync} = require('fs');
4
- const eyesIndexContent = `import "@applitools/eyes-cypress"`;
1
+ 'use strict'
2
+ const chalk = require('chalk')
3
+ const {writeFileSync, existsSync} = require('fs')
4
+ const eyesIndexContent = `import "@applitools/eyes-cypress"`
5
5
 
6
6
  function handleTypeScript(typeScriptFilePath) {
7
7
  if (!existsSync(typeScriptFilePath)) {
8
- writeFileSync(typeScriptFilePath, eyesIndexContent);
9
- console.log(chalk.cyan('TypeScript defined.'));
8
+ writeFileSync(typeScriptFilePath, eyesIndexContent)
9
+ console.log(chalk.cyan('TypeScript defined.'))
10
10
  } else {
11
- console.log(chalk.cyan('TypeScript already defined.'));
11
+ console.log(chalk.cyan('TypeScript already defined.'))
12
12
  }
13
13
  }
14
14
 
15
- module.exports = {handleTypeScript, eyesIndexContent};
15
+ module.exports = {handleTypeScript, eyesIndexContent}
@@ -1,7 +1,7 @@
1
- 'use strict';
1
+ 'use strict'
2
2
 
3
3
  function isCommandsDefined(content) {
4
- return !!content.match(/['"]@applitools\/eyes-cypress\/commands['"]\s*/);
4
+ return !!content.match(/['"]@applitools\/eyes-cypress\/commands['"]\s*/)
5
5
  }
6
6
 
7
- module.exports = isCommandsDefined;
7
+ module.exports = isCommandsDefined
@@ -1,7 +1,7 @@
1
- 'use strict';
1
+ 'use strict'
2
2
 
3
3
  function isPluginDefined(content) {
4
- return !!content.match(/require\s*\(\s*['"]@applitools\/eyes-cypress['"]\s*\)/);
4
+ return !!content.match(/require\s*\(\s*['"]@applitools\/eyes-cypress['"]\s*\)/)
5
5
  }
6
6
 
7
- module.exports = isPluginDefined;
7
+ module.exports = isPluginDefined