我正在将一个Protractor页面对象库从JavaScript转换为Typescript。我有一个静态实用程序方法刷新,直到元素存在(或达到超时限制)。
出于某种原因,我无法使用boolean
有价值的承诺作为thenable
构造,我无法弄清楚原因。错误消息为error TS2345: Argument of type '(value: boolean) => Promise<{}> | undefined' is not assignable to parameter of type '((value: boolean) => {} | IThenable<{}>) | undefined'.
Type '(value: boolean) => Promise<{}> | undefined' is not assignable to type '(value: boolean) => {} | IThenable<{}>'.
Type 'Promise<{}> | undefined' is not assignable to type '{} | IThenable<{}>'.
Type 'undefined' is not assignable to type '{} | IThenable<{}>'.
源代码如下,注释显示编译错误发生的位置。
我在我转换为Typescript的框架的纯JavaScript版本中使用了这种机制。我需要做什么才能将此方法转换为将要编译的Typescript?
import {browser, element, ElementFinder, ExpectedConditions} from 'protractor';
import * as wd from 'selenium-webdriver';
import {By} from "selenium-webdriver";
export class ExtendedExpectedConditions {
public static refreshUntilElementIsPresent(element: ElementFinder, numberOfSeconds: number = 30000,
refreshInterval: number = 5000): void {
this.refreshElement(element, numberOfSeconds, refreshInterval);
}
protected static refreshElement(element: ElementFinder, numberOfSeconds: number = 30000, refreshInterval:
number = 5000) {
//This line throws the compile error
element.isPresent().then(value => {
if (!value) {
if (numberOfSeconds <= 0) {
return new wd.promise.Promise(function (resolve, reject) {
reject('Element cannot be found after expected retry numbers');
})
}
browser.sleep(refreshInterval).then(() => {
browser.refresh().then(() => this.refreshUntilElementIsPresent(element, numberOfSeconds -
(refreshInterval / 1000)));
});
}
});
}
}
我的'package.json'如下:
{
"name": "my-project",
"version": "1.0.0",
"description": "A test suite",
"scripts": {
"tsc": "tsc",
"pretest": "npm run tsc",
"test": "node_modules/protractor/bin/protractor tmp/conf.js",
"start_selenium": "node_modules/protractor/node_modules/webdriver-manager/bin/webdriver-manager start",
"update_selenium": "node_modules/protractor/node_modules/webdriver-manager/bin/webdriver-manager update"
},
"author": aperson@someplace.com,
"dependencies": {
"@types/jasmine": "^2.5.52",
"@types/jasminewd2": "^2.0.2",
"@types/node": "^7.0.31",
"any-promise": "^1.3.0",
"jasmine-reporters": "^2.2.1",
"protractor": "^5.1.2",
"typescript": "^2.3.4"
}
}
我的tsconfig.json如下:
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"declaration": false,
"noImplicitAny": false,
"outDir": "tmp",
"types": ["jasmine", "node"],
"strict": true
},
"exclude": [
"node_modules"
]
}
我的conf.ts文件如下:
import {Config, browser, protractor} from "protractor";
let testsTimeout = 3600000;
let delayBrowserTimeInSeconds = 0;
export let config: Config = {
framework: 'jasmine2',
rootElement: 'body',
seleniumServerJar:'../node_modules/protractor/node_modules/webdriver-manager/selenium/selenium-server-standalone-3.4.0.jar',
chromeDriver: '../node_modules/protractor/node_modules/webdriver-manager/selenium/chromedriver_2.30',
specs: ['tests/*Spec.js'],
capabilities: {
browserName: 'chrome',
acceptSslCerts: true,
trustAllSSLCertificates: true,
chromeOptions: {
args: ['--no-sandbox']
},
},
baseUrl: 'https://www.someurl.com',
jasmineNodeOpts: {
defaultTimeoutInterval: testsTimeout,
showColors: true,
isVerbose: true
},
onPrepare: () => {
let origFn = browser.driver.controlFlow().execute;
browser.driver.controlFlow().execute = function () {
let args = arguments;
origFn.call(browser.driver.controlFlow(), function () {
return protractor.promise.delayed(delayBrowserTimeInSeconds * 100);
});
return origFn.apply(browser.driver.controlFlow(), args);
};
setTimeout(() => {
browser.driver.executeScript<[number, number]>(() => {
return [
window.screen.availWidth,
window.screen.availHeight
];
}).then((result: [number, number]) => {
browser.driver.manage().window().setSize(result[0], result[1]);
browser.driver.manage().window().maximize();
});
});
},
getPageTimeout: 120000,
allScriptsTimeout: testsTimeout
};
答案 0 :(得分:4)
你真正的问题似乎是类型库的作者对then
方法的回调参数有一个破碎的定义。您在问题中稍微错误地输入了错误消息,这使得查看正在发生的事情变得更加困难。
src/test.ts(17,34): error TS2345: Argument of type '(value: boolean) => Promise<{}> | undefined' is not assignable to parameter of type '((value: boolean) => {} | IThenable<{}>) | undefined'.
Type '(value: boolean) => Promise<{}> | undefined' is not assignable to type '(value: boolean) => {} | IThenable<{}>'.
Type 'Promise<{}> | undefined' is not assignable to type '{} | IThenable<{}>'.
Type 'undefined' is not assignable to type '{} | IThenable<{}>'.
因此,您向.then
提供的回调类型为(value: boolean) => Promise<{}> | undefined
,也就是说它返回Promise或返回undefined
。
但.then()
期望获得((value: boolean) => {} | IThenable<{}>) | undefined
(这是你失去亲密关系的地方)&#39;在问题中)也就是说功能或没有回调。当你给它一个函数时我们可以忽略undefined
,所以我们必须给它一个函数来返回一些东西或IThenable<something>
。此代码的作者已决定then
中的回调不允许返回undefined
。
因此,短期修复很简单:更改.then
回调,以便始终返回结果。
长期解决方案是向Selenium Webdriver的typescript绑定的作者报告问题,并要求他们允许回调返回{} | IThenable<{}> | undefined
。
你应该找到这个代码为你编译:
export class ExtendedExpectedConditions {
public static refreshUntilElementIsPresent(element: ElementFinder, numberOfSeconds: number = 30000,
refreshInterval: number = 5000): void {
this.refreshElement(element, numberOfSeconds, refreshInterval);
}
protected static refreshElement(element: ElementFinder, numberOfSeconds: number = 30000, refreshInterval:
number = 5000) {
//This line throws the compile error
element.isPresent().then(value => {
if (!value) {
if (numberOfSeconds <= 0) {
return wd.promise.rejected('Element cannot be found after expected retry numbers');
}
browser.sleep(refreshInterval).then(() => {
browser.refresh().then(() => this.refreshUntilElementIsPresent(element, numberOfSeconds -
(refreshInterval / 1000)));
});
}
return 42; // webdriver `.then` callback must return a result.
});
}
}
此外,由于某些原因,webdriver Promise的类型定义不会声明对象本身包含的.resolve()
和.reject()
方法,但您可以使用{{1}函数是一种更简单的方法来创建一个立即被拒绝的承诺。
答案 1 :(得分:0)
您得到的错误是正确的,如果您查看规格,您会看到量角器@returns {Promise<boolean>}
,请参阅规格here
您是否听说过TypeScript中的async / await
方法。它将使您的生活更轻松,您的代码更清洁。您的代码如下所示。这也应该消除你的打字错误。
public static refreshUntilElementIsPresent(element: ElementFinder, numberOfSeconds: number = 30000,
refreshInterval: number = 5000): void {
return this.refreshElement(element, numberOfSeconds, refreshInterval);
}
// Add async here
protected static async refreshElement(element: ElementFinder, numberOfSeconds: number = 30000, refreshInterval: number = 5000) {
// Wait untill the promise is resolved
const isPresent = await element.isPresent();
// Use the resolved promise
if (!isPresent) {
if (numberOfSeconds <= 0) {
// You can clean the Promise rejection and create 1 line of code
return Promise.reject('Element cannot be found after expected retry numbers');
}
// Wait for the rest
await browser.sleep(refreshInterval);
await browser.refresh();
return this.refreshUntilElementIsPresent(element, numberOfSeconds - (refreshInterval / 1000));
}
};