Browse Source

test: include extDb tests

Signed-off-by: Raju Udava <86527202+dstala@users.noreply.github.com>
pull/5601/head
Raju Udava 1 year ago
parent
commit
906db2dc9d
  1. 264
      tests/playwright/package-lock.json
  2. 1
      tests/playwright/package.json
  3. 17
      tests/playwright/pages/Dashboard/TreeView.ts
  4. 20
      tests/playwright/pages/Dashboard/common/Cell/DateTimeCell.ts
  5. 255
      tests/playwright/tests/db/timezone.spec.ts

264
tests/playwright/package-lock.json generated

@ -12,6 +12,7 @@
"body-parser": "^1.20.1",
"dayjs": "^1.11.7",
"express": "^4.18.2",
"knex": "^2.4.2",
"nocodb-sdk": "file:../../packages/nocodb-sdk",
"xlsx": "^0.18.5"
},
@ -1097,14 +1098,12 @@
"node_modules/colorette": {
"version": "2.0.19",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
"integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
"dev": true
"integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ=="
},
"node_modules/commander": {
"version": "9.4.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz",
"integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==",
"dev": true,
"engines": {
"node": "^12.20.0 || >=14"
}
@ -1408,6 +1407,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/escalade": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
"engines": {
"node": ">=6"
}
},
"node_modules/escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@ -1780,6 +1787,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/esm": {
"version": "3.2.25",
"resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz",
"integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==",
"engines": {
"node": ">=6"
}
},
"node_modules/espree": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
@ -2167,6 +2182,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-package-type": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
"integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/get-stdin": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
@ -2204,6 +2227,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/getopts": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/getopts/-/getopts-2.3.0.tgz",
"integrity": "sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA=="
},
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@ -2482,6 +2510,14 @@
"node": ">= 0.4"
}
},
"node_modules/interpret": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
"integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==",
"engines": {
"node": ">= 0.10"
}
},
"node_modules/ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
@ -2534,7 +2570,6 @@
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
"integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
"dev": true,
"dependencies": {
"has": "^1.0.3"
},
@ -2772,6 +2807,85 @@
"integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==",
"dev": true
},
"node_modules/knex": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/knex/-/knex-2.4.2.tgz",
"integrity": "sha512-tMI1M7a+xwHhPxjbl/H9K1kHX+VncEYcvCx5K00M16bWvpYPKAZd6QrCu68PtHAdIZNQPWZn0GVhqVBEthGWCg==",
"dependencies": {
"colorette": "2.0.19",
"commander": "^9.1.0",
"debug": "4.3.4",
"escalade": "^3.1.1",
"esm": "^3.2.25",
"get-package-type": "^0.1.0",
"getopts": "2.3.0",
"interpret": "^2.2.0",
"lodash": "^4.17.21",
"pg-connection-string": "2.5.0",
"rechoir": "^0.8.0",
"resolve-from": "^5.0.0",
"tarn": "^3.0.2",
"tildify": "2.0.0"
},
"bin": {
"knex": "bin/cli.js"
},
"engines": {
"node": ">=12"
},
"peerDependenciesMeta": {
"better-sqlite3": {
"optional": true
},
"mysql": {
"optional": true
},
"mysql2": {
"optional": true
},
"pg": {
"optional": true
},
"pg-native": {
"optional": true
},
"sqlite3": {
"optional": true
},
"tedious": {
"optional": true
}
}
},
"node_modules/knex/node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/knex/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/knex/node_modules/resolve-from": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
"integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
"engines": {
"node": ">=8"
}
},
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@ -2907,8 +3021,7 @@
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash.merge": {
"version": "4.6.2",
@ -3718,8 +3831,7 @@
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
},
"node_modules/path-to-regexp": {
"version": "0.1.7",
@ -3764,8 +3876,7 @@
"node_modules/pg-connection-string": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz",
"integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==",
"dev": true
"integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ=="
},
"node_modules/pg-int8": {
"version": "1.0.1",
@ -4093,6 +4204,17 @@
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true
},
"node_modules/rechoir": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz",
"integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==",
"dependencies": {
"resolve": "^1.20.0"
},
"engines": {
"node": ">= 10.13.0"
}
},
"node_modules/regexp.prototype.flags": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
@ -4135,7 +4257,6 @@
"version": "1.22.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
"integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
"dev": true,
"dependencies": {
"is-core-module": "^2.9.0",
"path-parse": "^1.0.7",
@ -4609,7 +4730,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
@ -4655,6 +4775,14 @@
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true
},
"node_modules/tarn": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz",
"integrity": "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==",
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@ -4667,6 +4795,14 @@
"integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
"dev": true
},
"node_modules/tildify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz",
"integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==",
"engines": {
"node": ">=8"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@ -5736,14 +5872,12 @@
"colorette": {
"version": "2.0.19",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
"integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
"dev": true
"integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ=="
},
"commander": {
"version": "9.4.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz",
"integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==",
"dev": true
"integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw=="
},
"concat-map": {
"version": "0.0.1",
@ -5979,6 +6113,11 @@
"is-symbol": "^1.0.2"
}
},
"escalade": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
},
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@ -6241,6 +6380,11 @@
"integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
"dev": true
},
"esm": {
"version": "3.2.25",
"resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz",
"integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA=="
},
"espree": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
@ -6541,6 +6685,11 @@
"has-symbols": "^1.0.3"
}
},
"get-package-type": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
"integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q=="
},
"get-stdin": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
@ -6563,6 +6712,11 @@
"get-intrinsic": "^1.1.1"
}
},
"getopts": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/getopts/-/getopts-2.3.0.tgz",
"integrity": "sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA=="
},
"glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@ -6760,6 +6914,11 @@
"side-channel": "^1.0.4"
}
},
"interpret": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
"integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw=="
},
"ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
@ -6794,7 +6953,6 @@
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
"integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
"dev": true,
"requires": {
"has": "^1.0.3"
}
@ -6963,6 +7121,47 @@
"integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==",
"dev": true
},
"knex": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/knex/-/knex-2.4.2.tgz",
"integrity": "sha512-tMI1M7a+xwHhPxjbl/H9K1kHX+VncEYcvCx5K00M16bWvpYPKAZd6QrCu68PtHAdIZNQPWZn0GVhqVBEthGWCg==",
"requires": {
"colorette": "2.0.19",
"commander": "^9.1.0",
"debug": "4.3.4",
"escalade": "^3.1.1",
"esm": "^3.2.25",
"get-package-type": "^0.1.0",
"getopts": "2.3.0",
"interpret": "^2.2.0",
"lodash": "^4.17.21",
"pg-connection-string": "2.5.0",
"rechoir": "^0.8.0",
"resolve-from": "^5.0.0",
"tarn": "^3.0.2",
"tildify": "2.0.0"
},
"dependencies": {
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"requires": {
"ms": "2.1.2"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"resolve-from": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
"integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="
}
}
},
"levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@ -7059,8 +7258,7 @@
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"lodash.merge": {
"version": "4.6.2",
@ -7711,8 +7909,7 @@
"path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
},
"path-to-regexp": {
"version": "0.1.7",
@ -7743,8 +7940,7 @@
"pg-connection-string": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz",
"integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==",
"dev": true
"integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ=="
},
"pg-int8": {
"version": "1.0.1",
@ -7983,6 +8179,14 @@
}
}
},
"rechoir": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz",
"integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==",
"requires": {
"resolve": "^1.20.0"
}
},
"regexp.prototype.flags": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
@ -8010,7 +8214,6 @@
"version": "1.22.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
"integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
"dev": true,
"requires": {
"is-core-module": "^2.9.0",
"path-parse": "^1.0.7",
@ -8355,8 +8558,7 @@
"supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
},
"table": {
"version": "6.8.1",
@ -8391,6 +8593,11 @@
}
}
},
"tarn": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz",
"integrity": "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ=="
},
"text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@ -8403,6 +8610,11 @@
"integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
"dev": true
},
"tildify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz",
"integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw=="
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",

1
tests/playwright/package.json

@ -46,6 +46,7 @@
"body-parser": "^1.20.1",
"dayjs": "^1.11.7",
"express": "^4.18.2",
"knex": "^2.4.2",
"nocodb-sdk": "file:../../packages/nocodb-sdk",
"xlsx": "^0.18.5"
}

17
tests/playwright/pages/Dashboard/TreeView.ts

@ -48,6 +48,23 @@ export class TreeViewPage extends BasePage {
await this.get().locator(`.nc-project-tree-tbl-${title}`).focus();
}
async openBase({ title }: { title: string }) {
const nodes = await this.get().locator(`.ant-collapse`);
// loop through nodes.count() to find the node with title
for (let i = 0; i < (await nodes.count()); i++) {
const node = nodes.nth(i);
const nodeTitle = await node.innerText();
// check if nodeTitle contains title
if (nodeTitle.includes(title)) {
// click on node
await node.click();
break;
}
}
await this.rootPage.waitForTimeout(1000);
}
// assumption: first view rendered is always GRID
//
async openTable({

20
tests/playwright/pages/Dashboard/common/Cell/DateTimeCell.ts

@ -23,7 +23,7 @@ export class DateTimeCellPageObject extends BasePage {
}
async save() {
await this.rootPage.locator('button:has-text("Ok")').click();
await this.rootPage.locator('button:has-text("Ok"):visible').click();
}
async selectDate({
@ -36,15 +36,15 @@ export class DateTimeCellPageObject extends BasePage {
const [year, month, day] = date.split('-');
// configure year
await this.rootPage.locator('.ant-picker-year-btn').click();
await this.rootPage.locator('.ant-picker-year-btn:visible').click();
await this.rootPage.locator(`td[title="${year}"]`).click();
// configure month
await this.rootPage.locator('.ant-picker-month-btn').click();
await this.rootPage.locator('.ant-picker-month-btn:visible').click();
await this.rootPage.locator(`td[title="${year}-${month}"]`).click();
// configure day
await this.rootPage.locator(`td[title="${year}-${month}-${day}"]`).click();
await this.rootPage.locator(`td[title="${year}-${month}-${day}"]:visible`).click();
}
async selectTime({
@ -60,14 +60,20 @@ export class DateTimeCellPageObject extends BasePage {
second?: number | null;
}) {
await this.rootPage
.locator(`.ant-picker-time-panel-column:nth-child(1) > .ant-picker-time-panel-cell:nth-child(${hour + 1})`)
.locator(
`.ant-picker-time-panel-column:nth-child(1) > .ant-picker-time-panel-cell:nth-child(${hour + 1}):visible`
)
.click();
await this.rootPage
.locator(`.ant-picker-time-panel-column:nth-child(2) > .ant-picker-time-panel-cell:nth-child(${minute + 1})`)
.locator(
`.ant-picker-time-panel-column:nth-child(2) > .ant-picker-time-panel-cell:nth-child(${minute + 1}):visible`
)
.click();
if (second != null) {
await this.rootPage
.locator(`.ant-picker-time-panel-column:nth-child(3) > .ant-picker-time-panel-cell:nth-child(${second + 1})`)
.locator(
`.ant-picker-time-panel-column:nth-child(3) > .ant-picker-time-panel-cell:nth-child(${second + 1}):visible`
)
.click();
}
}

255
tests/playwright/tests/db/timezone.spec.ts

@ -1,6 +1,7 @@
import { expect, test } from '@playwright/test';
import { DashboardPage } from '../../pages/Dashboard';
import setup from '../../setup';
import { knex } from 'knex';
import { Api, UITypes } from 'nocodb-sdk';
let api: Api<any>, records: any[];
@ -25,7 +26,7 @@ const rowAttributes = [
{ Id: 3, DateTime: '2020-12-31 20:00:00-04:00' },
];
test.describe('Timezone : Europe/Berlin', () => {
test.describe('Timezone : Japan/Tokyo', () => {
let dashboard: DashboardPage;
let context: any;
@ -57,14 +58,15 @@ test.describe('Timezone : Europe/Berlin', () => {
await page.reload();
});
// DST independent test
test.use({
locale: 'de-DE', // Change to German locale
timezoneId: 'Europe/Berlin',
locale: 'ja-JP', // Change to Japanese locale
timezoneId: 'Asia/Tokyo', // Set timezone to Tokyo timezone
});
/*
* This test is to verify the display value of DateTime column in the grid
* when the timezone is set to Europe/Berlin
* when the timezone is set to Asia/Tokyo
*
* The test inserts 3 rows using API
* 1. DateTime inserted without timezone
@ -72,24 +74,24 @@ test.describe('Timezone : Europe/Berlin', () => {
* 3. DateTime inserted with timezone (UTC-4)
*
* Expected display values:
* Display value is converted to Europe/Berlin
* Display value is converted to Asia/Tokyo
*/
test('API insert, verify display value', async () => {
await dashboard.treeView.openTable({ title: 'dateTimeTable' });
// DateTime inserted using API without timezone is converted to UTC
// Display value is converted to Europe/Berlin
await dashboard.grid.cell.verifyDateCell({ index: 0, columnHeader: 'DateTime', value: '2021-01-01 01:00' });
// Display value is converted to Asia/Tokyo
await dashboard.grid.cell.verifyDateCell({ index: 0, columnHeader: 'DateTime', value: '2021-01-01 09:00' });
// DateTime inserted using API with timezone is converted to UTC
// Display value is converted to Europe/Berlin
await dashboard.grid.cell.verifyDateCell({ index: 1, columnHeader: 'DateTime', value: '2021-01-01 01:00' });
await dashboard.grid.cell.verifyDateCell({ index: 2, columnHeader: 'DateTime', value: '2021-01-01 01:00' });
// Display value is converted to Asia/Tokyo
await dashboard.grid.cell.verifyDateCell({ index: 1, columnHeader: 'DateTime', value: '2021-01-01 09:00' });
await dashboard.grid.cell.verifyDateCell({ index: 2, columnHeader: 'DateTime', value: '2021-01-01 09:00' });
});
/*
* This test is to verify the API read response of DateTime column
* when the timezone is set to Europe/Berlin
* when the timezone is set to Asia/Tokyo
*
* The test inserts 3 rows using API
* 1. DateTime inserted without timezone
@ -313,3 +315,234 @@ test.describe('Timezone', () => {
await dashboard.grid.cell.verifyDateCell({ index: 1, columnHeader: 'DateTime', value: '2021-01-01 08:00' });
});
});
async function createTableWithDateTimeColumn(database: string) {
if (database === 'pg') {
const config = {
client: 'pg',
connection: {
host: 'localhost',
port: 5432,
user: 'postgres',
password: 'password',
database: 'postgres',
multipleStatements: true,
},
searchPath: ['public', 'information_schema'],
pool: { min: 0, max: 5 },
};
const config2 = {
...config,
connection: {
...config.connection,
database: 'datetimetable',
},
};
const pgknex = knex(config);
await pgknex.raw(`DROP DATABASE IF EXISTS dateTimeTable`);
await pgknex.raw(`CREATE DATABASE dateTimeTable`);
await pgknex.destroy();
const pgknex2 = knex(config2);
await pgknex2.raw(`
CREATE TABLE my_table (
title SERIAL PRIMARY KEY,
datetime_without_tz TIMESTAMP WITHOUT TIME ZONE,
datetime_with_tz TIMESTAMP WITH TIME ZONE
);
SET timezone = 'Asia/Hong_Kong';
SELECT pg_sleep(1);
INSERT INTO my_table (datetime_without_tz, datetime_with_tz)
VALUES
('2023-04-27 10:00:00', '2023-04-27 12:30:00'),
('2023-04-27 10:00:00+05:30', '2023-04-27 10:00:00+05:30');
`);
await pgknex2.destroy();
} else if (database === 'mysql') {
const config = {
client: 'mysql',
connection: {
host: 'localhost',
port: 3306,
user: 'root',
password: 'password',
database: 'sakila',
},
pool: { min: 0, max: 5 },
};
const config2 = {
...config,
connection: {
...config.connection,
database: 'datetimetable',
},
};
const mysqlknex = knex(config);
await mysqlknex.raw(`DROP DATABASE IF EXISTS dateTimeTable`);
await mysqlknex.raw(`CREATE DATABASE dateTimeTable`);
await mysqlknex.destroy();
const mysqlknex2 = knex(config2);
await mysqlknex2.raw(`
CREATE TABLE my_table (
title INT AUTO_INCREMENT PRIMARY KEY,
datetime_without_tz DATETIME,
datetime_with_tz TIMESTAMP
);
SET time_zone = '+08:00';
SELECT sleep(1);
INSERT INTO my_table (datetime_without_tz, datetime_with_tz)
VALUES
('2023-04-27 10:00:00', '2023-04-27 12:30:00'),
('2023-04-27 10:00:00+05:30', '2023-04-27 10:00:00+05:30');
`);
await mysqlknex2.destroy();
} else if (database === 'sqlite') {
const config = {
client: 'sqlite3',
connection: {
filename: './mydb.sqlite3',
},
useNullAsDefault: true,
pool: { min: 0, max: 5 },
};
// SQLite supports just one type of datetime
// Timezone information, if specified is stored as is in the database
// https://www.sqlite.org/lang_datefunc.html
const sqliteknex = knex(config);
await sqliteknex.raw(`DROP TABLE IF EXISTS my_table`);
await sqliteknex.raw(`
CREATE TABLE my_table (
title INTEGER PRIMARY KEY AUTOINCREMENT,
datetime_without_tz DATETIME,
datetime_with_tz DATETIME
)
`);
const datetimeData = [
['2023-04-27 10:00:00', '2023-04-27 10:00:00'],
['2023-04-27 10:00:00+05:30', '2023-04-27 10:00:00+05:30'],
];
for (const data of datetimeData) {
await sqliteknex('my_table').insert({
datetime_without_tz: data[0],
datetime_with_tz: data[1],
});
}
await sqliteknex.destroy();
}
}
test.describe('External DB - DateTime column', async () => {
let dashboard: DashboardPage;
let context: any;
test.use({
locale: 'zh-HK',
timezoneId: 'Asia/Hong_Kong',
});
test.beforeEach(async ({ page }) => {
context = await setup({ page, isEmptyProject: true });
dashboard = new DashboardPage(page, context.project);
api = new Api({
baseURL: `http://localhost:8080/`,
headers: {
'xc-auth': context.token,
},
});
await createTableWithDateTimeColumn(context.dbType);
await api.base.create(context.project.id, {
alias: 'datetimetable',
type: 'pg',
config: {
client: 'pg',
connection: {
host: 'localhost',
port: '5432',
user: 'postgres',
password: 'password',
database: 'datetimetable',
},
searchPath: ['public'],
},
inflection_column: 'camelize',
inflection_table: 'camelize',
});
await dashboard.rootPage.reload();
});
test('Verify display value, UI insert, API response', async () => {
await dashboard.treeView.openBase({ title: 'datetimetable' });
await dashboard.treeView.openTable({ title: 'MyTable' });
// display value for datetime column without tz should be same as stored value
// display value for datetime column with tz should be converted to browser timezone (HK in this case)
await dashboard.grid.cell.verifyDateCell({
index: 0,
columnHeader: 'DatetimeWithoutTz',
value: '2023-04-27 10:00',
});
await dashboard.grid.cell.verifyDateCell({
index: 1,
columnHeader: 'DatetimeWithoutTz',
value: '2023-04-27 10:00',
});
await dashboard.grid.cell.verifyDateCell({
index: 0,
columnHeader: 'DatetimeWithTz',
value: '2023-04-27 12:30',
});
await dashboard.grid.cell.verifyDateCell({
index: 1,
columnHeader: 'DatetimeWithTz',
value: '2023-04-27 12:30',
});
// Insert new row
await dashboard.grid.cell.dateTime.setDateTime({
index: 2,
columnHeader: 'DatetimeWithoutTz',
dateTime: '2023-04-27 10:00:00',
});
await dashboard.rootPage.waitForTimeout(1000);
await dashboard.grid.cell.dateTime.setDateTime({
index: 2,
columnHeader: 'DatetimeWithTz',
dateTime: '2023-04-27 12:30:00',
});
// verify API response
// Note that, for UI inserted records - second part of datetime may be non-zero (though not shown in UI)
// Hence, we skip seconds from API response
//
const records = await api.dbTableRow.list('noco', context.project.id, 'MyTable', { limit: 10 });
let dateTimeWithoutTz = records.list.map(record => record.DatetimeWithoutTz);
let dateTimeWithTz = records.list.map(record => record.DatetimeWithTz);
const expectedDateTimeWithoutTz = ['2023-04-27 10:00:00', '2023-04-27 10:00:00', '2023-04-27 10:00:00'];
const expectedDateTimeWithTz = ['2023-04-27T04:30:00.000Z', '2023-04-27T04:30:00.000Z', '2023-04-27T04:30:00.000Z'];
dateTimeWithoutTz = dateTimeWithoutTz.map(dateTimeStr => {
const [datePart, timePart] = dateTimeStr.split(' ');
const updatedTimePart = timePart.split(':').slice(0, 2).join(':') + ':00';
return `${datePart} ${updatedTimePart}`;
});
dateTimeWithTz = dateTimeWithTz.map(dateTimeStr => {
const dateObj = new Date(dateTimeStr);
dateObj.setSeconds(0);
return dateObj.toISOString();
});
expect(dateTimeWithoutTz).toEqual(expectedDateTimeWithoutTz);
expect(dateTimeWithTz).toEqual(expectedDateTimeWithTz);
});
});

Loading…
Cancel
Save