test: add more tests

This commit is contained in:
George He
2024-01-17 13:46:12 +08:00
parent 73670f8f93
commit bc2b07de23
4 changed files with 134 additions and 96 deletions

14
package-lock.json generated
View File

@@ -9362,6 +9362,14 @@
"node": ">=8"
}
},
"node_modules/browser-extension-url-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/browser-extension-url-match/-/browser-extension-url-match-1.0.0.tgz",
"integrity": "sha512-LfIs9SYgPjYksjxkgOVYZhxMIroR56isQB3YHTAmzunWuT9qrH6Fxt7TD9/s9MoKo7GP37JZbLlZhL9vwQAk3w==",
"dependencies": {
"fancy-regex": "^0.5.4"
}
},
"node_modules/browser-process-hrtime": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz",
@@ -13443,6 +13451,11 @@
"integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==",
"dev": true
},
"node_modules/fancy-regex": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/fancy-regex/-/fancy-regex-0.5.4.tgz",
"integrity": "sha512-O6qfjtMnrPRs+3XOavCxGQDFaMS9K1vEsQMhPowqx2P/h1fDCvK5RUyeWeyDusMH2FkSHAsRE3IbSBMMg53fmw=="
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -24969,6 +24982,7 @@
"apiconnect-wsdl": "1.8.31",
"aws4": "^1.12.0",
"axios": "^1.4.0",
"browser-extension-url-match": "^1.0.0",
"chai": "^4.3.4",
"chai-json-schema": "1.5.1",
"change-case": "^4.1.2",

View File

@@ -49,6 +49,7 @@
"apiconnect-wsdl": "1.8.31",
"aws4": "^1.12.0",
"axios": "^1.4.0",
"browser-extension-url-match": "^1.0.0",
"chai": "^4.3.4",
"chai-json-schema": "1.5.1",
"change-case": "^4.1.2",

View File

@@ -3,7 +3,7 @@ import url from 'node:url';
import { describe, expect, it } from '@jest/globals';
import { PropertyList } from '../base';
import { QueryParam, setUrlParser, Url } from '../urls';
import { QueryParam, setUrlParser, Url, UrlMatchPattern } from '../urls';
import { Variable } from '../variables';
describe('test Certificate object', () => {
@@ -75,12 +75,17 @@ describe('test Certificate object', () => {
// static methods
const urlStr = 'https://myhost.com/path1/path2';
const urlOptions = Url.parse(urlStr);
const urlOpt = new Url(urlOptions || '');
expect(urlOpt.toString()).toEqual(urlStr);
const urlObj = new Url(urlOptions || '');
expect(urlObj.toString()).toEqual(urlStr);
});
it('test UrlMatchPattern', () => {
const pattern = 'https://*.insomnia.com/*';
const matchPattern = new UrlMatchPattern(pattern);
expect(matchPattern.getProtocols()).toEqual(['https']);
expect(matchPattern.test('https://*.insomnia.com')).toBeTruthy();
expect(matchPattern.toString()).toEqual(pattern);
});
});

View File

@@ -1,3 +1,5 @@
import { MatcherOrInvalid, matchPattern } from 'browser-extension-url-match';
import { Property, PropertyBase, PropertyList } from './base';
import { Variable, VariableList } from './variables';
@@ -363,22 +365,26 @@ export class Url extends PropertyBase {
}
}
// interface Matcher {
// match(pattern: string): boolean;
// }
// UrlMatchPattern implements chrome extension match patterns:
// https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns
export class UrlMatchPattern extends Property {
// scheme
scheme: 'http:' | 'https:' | '*' | 'file:';
// scheme: 'http:' | 'https:' | '*' | 'file:';
// host
// About wildcard:
// If you use a wildcard in the host pattern
// it must be the first or only character, and it must be followed by a period (.) or forward slash (/).
host: string;
// host: string;
// path:
// Must contain at least a forward slash
// The slash by itself matches any path.
path: string;
// path: string;
private port: string;
// private port: string;
// Special cases: https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns#special
// "<all_urls>"
@@ -386,125 +392,137 @@ export class UrlMatchPattern extends Property {
// "http://localhost/*"
// It doesn't support match patterns for top Level domains (TLD).
private matcher: MatcherOrInvalid;
private pattern: string;
constructor(pattern: string) {
super();
const patternObj = UrlMatchPattern.parseAndValidate(pattern);
this.scheme = patternObj.scheme;
this.host = patternObj.host;
this.path = patternObj.path;
this.port = patternObj.port;
// const patternObj = UrlMatchPattern.parse(pattern);
this.pattern = pattern;
this.matcher = matchPattern(pattern).assertValid();
// this.scheme = patternObj.scheme;
// this.host = patternObj.host;
// this.path = patternObj.path;
// this.port = patternObj.port;
}
static parseAndValidate(pattern: string): {
scheme: 'http:' | 'https:' | '*' | 'file:';
host: string;
path: string;
port: string;
} {
// TODO: validate the pattern
const urlObj = new Url(pattern);
// private static parse(pattern: string): {
// scheme: 'http:' | 'https:' | '*' | 'file:';
// host: string;
// path: string;
// port: string;
// } {
// const urlObj = new Url(pattern);
if (!urlObj || urlObj.host.length === 0) {
throw Error(`match pattern (${pattern}) is invalid and failed to parse`);
}
// if (!urlObj || urlObj.host.length === 0) {
// throw Error(`match pattern (${pattern}) is invalid and failed to parse`);
// }
if (urlObj.protocol !== 'http:' && urlObj.protocol !== 'https:' && urlObj.protocol !== '*' && urlObj.protocol !== 'file:') {
throw Error(`scheme (${urlObj.protocol}) is invalid and failed to parse`);
}
// if (urlObj.protocol !== 'http:' && urlObj.protocol !== 'https:' && urlObj.protocol !== '*' && urlObj.protocol !== 'file:') {
// throw Error(`scheme (${urlObj.protocol}) is invalid and failed to parse`);
// }
return {
scheme: urlObj.protocol,
host: urlObj.getHost(),
path: urlObj.getPath() || '/',
port: urlObj.port || '',
};
}
// return {
// scheme: urlObj.protocol,
// host: urlObj.getHost(),
// path: urlObj.getPath() || '/',
// port: urlObj.port || '',
// };
// }
static readonly MATCH_ALL_URLS: string = '<all_urls>';
static pattern: string | undefined = undefined; // TODO: its usage is unknown
static readonly PROTOCOL_DELIMITER: string = '+';
// TODO: the url can not start with -
private readonly starRegPattern = '[a-zA-Z0-9\-]*';
// private readonly starRegPattern = '[a-zA-Z0-9\-]*';
getProtocols(): string[] {
switch (this.scheme) {
case 'http:':
return ['http'];
case 'https:':
return ['https'];
case '*':
return ['http', 'https'];
case 'file:':
return ['file'];
default:
throw `invalid scheme ${this.scheme}`;
}
const protocolEndPos = this.pattern.indexOf(':');
const protocolPattern = this.pattern.slice(0, protocolEndPos);
const protocols = protocolPattern.split(UrlMatchPattern.PROTOCOL_DELIMITER);
return protocols.map(protocol => protocol.replace(':', ''));
}
test(urlStr: string) {
const urlObj = Url.parse(urlStr);
if (!urlObj) {
return false;
}
return this.testProtocol(urlObj.protocol)
&& this.testHost(urlObj.host.join('/'))
&& this.testPort(urlObj.port || '', urlObj.protocol)
&& urlObj?.path && this.testPath(urlObj.path.join('/'));
return this.matcher.match(urlStr);
}
testHost(host: string) {
const hostRegPattern = new RegExp(this.host.replace('*', this.starRegPattern), 'ig');
return hostRegPattern.test(host);
}
// testHost(hostStr: string) {
// const protocolEndPos = this.pattern.indexOf(':');
// const pathBegPos = this.pattern.indexOf('/', 3);
// const hostOnlyPattern = '*' + this.pattern.slice(protocolEndPos + 3, pathBegPos) + '*';
// const hostOnlyMatcher = matchPattern(hostOnlyPattern);
testPath(path: string) {
const pathRegPattern = new RegExp(this.path.replace('*', this.starRegPattern), 'ig');
return pathRegPattern.test(path);
}
// return hostOnlyMatcher.match(hostStr);
// }
// TODO: it is confused to verify both port and protocol
// testPort verifies both port and protocol, but not the relationship between them
testPort(port: string, protocol: string) {
if (!this.testProtocol(protocol)) {
return false;
}
// testPath(pathStr: string) {
// const pathBegPos = this.pattern.indexOf('/', 3);
// const pathOnlyPattern = '*' + '*://*' + this.pattern.slice(pathBegPos);
// const pathOnlyMatcher = matchPattern(pathOnlyPattern);
const portRegPattern = new RegExp(this.port.replace('*', this.starRegPattern), 'ig');
if (!portRegPattern.test(port)) {
return false;
}
// return pathOnlyMatcher.match(pathStr);
// }
return true;
}
// // TODO: it is confusing to verify both port and protocol
// testPort(port: string, protocol: string) {
// const protocolEndPos = this.pattern.indexOf(':');
// const protocolPattern = this.pattern.slice(0, protocolEndPos);
// if (protocolPattern === '*') {
// return true;
// }
// const protocolMatcher = matchPattern(protocolPattern + '://*/*');
// if (protocolMatcher.match(p))
testProtocol(protocol: string) {
switch (protocol) {
case 'http:':
return this.scheme === 'http:' || this.scheme === '*';
case 'https:':
return this.scheme === 'https:' || this.scheme === '*';
case '*':
return this.scheme === 'http:' || this.scheme === 'https:' || this.scheme === '*';
case 'file:':
return this.scheme === 'file:';
default:
throw `invalid scheme ${protocol}`;
}
}
// const portBeg = this.pattern.indexOf(':', 2);
// const portEnd = this.pattern.indexOf('/', 3);
// const portPattern = this.pattern.slice(portBeg, portEnd);
// if (portPattern === '') {
// }
// const pathOnlyPattern = '*' + '*://*' + this.pattern.slice(pathBegPos);
// const pathOnlyMatcher = matchPattern(pathOnlyPattern);
// // return pathOnlyMatcher.match(pathStr);
// // if (!this.testProtocol(protocol)) {
// // return false;
// // }
// // const portRegPattern = new RegExp(this.port.replace('*', this.starRegPattern), 'ig');
// // if (!portRegPattern.test(port)) {
// // return false;
// // }
// // return true;
// }
// testProtocol(protocol: string) {
// switch (protocol) {
// case 'http:':
// return this.scheme === 'http:' || this.scheme === '*';
// case 'https:':
// return this.scheme === 'https:' || this.scheme === '*';
// case '*':
// return this.scheme === 'http:' || this.scheme === 'https:' || this.scheme === '*';
// case 'file:':
// return this.scheme === 'file:';
// default:
// throw `invalid scheme ${protocol}`;
// }
// }
toString() {
return `${this.scheme}//${this.host}${this.path}`;
return this.pattern;
}
update(pattern: string) {
const patternObj = UrlMatchPattern.parseAndValidate(pattern);
this.scheme = patternObj.scheme;
this.host = patternObj.host.join('/');
this.path = patternObj.path.join('/');
this.port = patternObj.port;
this.pattern = pattern;
this.matcher = matchPattern(pattern);
}
}