MOBILE-3947 reminders: Fix tests
parent
21d0dc6821
commit
44606242fd
|
@ -781,13 +781,10 @@ class behat_app extends behat_app_helper {
|
||||||
/**
|
/**
|
||||||
* Sets a field to the given text value in the app.
|
* Sets a field to the given text value in the app.
|
||||||
*
|
*
|
||||||
* Currently this only works for input fields which must be identified using a partial or
|
|
||||||
* exact match on the placeholder text.
|
|
||||||
*
|
|
||||||
* @Given /^I set the field "((?:[^"]|\\")+)" to "((?:[^"]|\\")*)" in the app$/
|
* @Given /^I set the field "((?:[^"]|\\")+)" to "((?:[^"]|\\")*)" in the app$/
|
||||||
* @param string $field Text identifying field
|
* @param string $field Text identifying the field.
|
||||||
* @param string $value Value for field
|
* @param string $value Value to set. In select fields, this can be either the value or text included in the select option.
|
||||||
* @throws DriverException If the field set doesn't work
|
* @throws DriverException If the field set doesn't work.
|
||||||
*/
|
*/
|
||||||
public function i_set_the_field_in_the_app(string $field, string $value) {
|
public function i_set_the_field_in_the_app(string $field, string $value) {
|
||||||
$field = addslashes_js($field);
|
$field = addslashes_js($field);
|
||||||
|
|
|
@ -16,52 +16,48 @@ Feature: Set a new reminder on activity
|
||||||
| assign | C1 | assign01 | Assignment 01 | ## yesterday ## | ## now +70 minutes ## |
|
| assign | C1 | assign01 | Assignment 01 | ## yesterday ## | ## now +70 minutes ## |
|
||||||
| assign | C1 | assign02 | Assignment 02 | ## yesterday ## | ## 1 January 2050 ## |
|
| assign | C1 | assign02 | Assignment 02 | ## yesterday ## | ## 1 January 2050 ## |
|
||||||
|
|
||||||
@ionic7_failure
|
|
||||||
Scenario: Add, delete and update reminder on activity
|
Scenario: Add, delete and update reminder on activity
|
||||||
Given I entered the assign activity "Assignment 01" on course "Course 1" as "student1" in the app
|
Given I entered the assign activity "Assignment 01" on course "Course 1" as "student1" in the app
|
||||||
|
|
||||||
Then I should not find "Set a reminder for \"Assignment 01\" (Opened)" in the app
|
Then I should not find "Set a reminder for \"Assignment 01\" (Opened)" in the app
|
||||||
And I should find "Set a reminder for \"Assignment 01\" (Due)" in the app
|
And I should not find "Reminder set for" in the app
|
||||||
And "Set a reminder for \"Assignment 01\" (Due)" should not be selected in the app
|
But I should find "Set a reminder for \"Assignment 01\" (Due)" in the app
|
||||||
|
|
||||||
# Default set
|
# Default set
|
||||||
When I press "Set a reminder for \"Assignment 01\" (Due)" in the app
|
When I press "Set a reminder for \"Assignment 01\" (Due)" in the app
|
||||||
Then I should find "Reminder set for " in the app
|
Then I should find "Reminder set for" in the app
|
||||||
And "Set a reminder for \"Assignment 01\" (Due)" should be selected in the app
|
|
||||||
|
|
||||||
# Set from list
|
# Set from list
|
||||||
When I press "Set a reminder for \"Assignment 01\" (Due)" in the app
|
When I press "Set a reminder for \"Assignment 01\" (Due)" in the app
|
||||||
Then I should find "Set a reminder" in the app
|
Then I should find "Set a reminder" in the app
|
||||||
And "At the time of the event" should be selected in the app
|
And "At the time of the event" should be selected in the app
|
||||||
And "1 hour before" should not be selected in the app
|
But "1 hour before" should not be selected in the app
|
||||||
When I press "1 hour before" in the app
|
When I press "1 hour before" in the app
|
||||||
Then I should find "Reminder set for " in the app
|
Then I should find "Reminder set for" in the app
|
||||||
And "Set a reminder for \"Assignment 01\" (Due)" should be selected in the app
|
|
||||||
|
|
||||||
# Custom set
|
# Custom set
|
||||||
When I press "Set a reminder for \"Assignment 01\" (Due)" in the app
|
When I press "Set a reminder for \"Assignment 01\" (Due)" in the app
|
||||||
Then I should find "Set a reminder" in the app
|
Then I should find "Set a reminder" in the app
|
||||||
And "At the time of the event" should not be selected in the app
|
|
||||||
And "1 hour before" should be selected in the app
|
And "1 hour before" should be selected in the app
|
||||||
|
But "At the time of the event" should not be selected in the app
|
||||||
When I press "Custom..." in the app
|
When I press "Custom..." in the app
|
||||||
Then I should find "Custom reminder" in the app
|
Then I should find "Custom reminder" in the app
|
||||||
When I set the following fields to these values in the app:
|
When I set the following fields to these values in the app:
|
||||||
| Value | 4 |
|
| Value | 4 |
|
||||||
| Units | minutes |
|
| Units | minutes |
|
||||||
And I press "Set reminder" in the app
|
And I press "Set reminder" in the app
|
||||||
Then I should find "Reminder set for " in the app
|
Then I should find "Reminder set for" in the app
|
||||||
And "Set a reminder for \"Assignment 01\" (Due)" should be selected in the app
|
|
||||||
|
|
||||||
# Remove
|
# Remove
|
||||||
When I press "Set a reminder for \"Assignment 01\" (Due)" in the app
|
When I press "Set a reminder for \"Assignment 01\" (Due)" in the app
|
||||||
Then "4 minutes before" should be selected in the app
|
Then "4 minutes before" should be selected in the app
|
||||||
When I press "Delete reminder" in the app
|
When I press "Delete reminder" in the app
|
||||||
Then I should find "Reminder deleted" in the app
|
Then I should find "Reminder deleted" in the app
|
||||||
And "Set a reminder for \"Assignment 01\" (Due)" should not be selected in the app
|
But I should not find "Reminder set for" in the app
|
||||||
|
|
||||||
# Set and check reminder
|
# Set and check reminder
|
||||||
When I press "Set a reminder for \"Assignment 01\" (Due)" in the app
|
When I press "Set a reminder for \"Assignment 01\" (Due)" in the app
|
||||||
Then I should find "Reminder set for " in the app
|
Then I should find "Reminder set for" in the app
|
||||||
When I press "Set a reminder for \"Assignment 01\" (Due)" in the app
|
When I press "Set a reminder for \"Assignment 01\" (Due)" in the app
|
||||||
And I press "Custom..." in the app
|
And I press "Custom..." in the app
|
||||||
Then I should find "Custom reminder" in the app
|
Then I should find "Custom reminder" in the app
|
||||||
|
@ -69,7 +65,7 @@ Feature: Set a new reminder on activity
|
||||||
| Value | 69 |
|
| Value | 69 |
|
||||||
| Units | minutes |
|
| Units | minutes |
|
||||||
And I press "Set reminder" in the app
|
And I press "Set reminder" in the app
|
||||||
Then I should find "Reminder set for " in the app
|
Then I should find "Reminder set for" in the app
|
||||||
When I wait "50" seconds
|
When I wait "50" seconds
|
||||||
Then a notification with title "Due: Assignment 01" is present in the app
|
Then a notification with title "Due: Assignment 01" is present in the app
|
||||||
And I close a notification with title "Due: Assignment 01" in the app
|
And I close a notification with title "Due: Assignment 01" in the app
|
||||||
|
@ -82,9 +78,9 @@ Feature: Set a new reminder on activity
|
||||||
| Value | 68 |
|
| Value | 68 |
|
||||||
| Units | minutes |
|
| Units | minutes |
|
||||||
And I press "Set reminder" in the app
|
And I press "Set reminder" in the app
|
||||||
Then I should find "Reminder set for " in the app
|
Then I should find "Reminder set for" in the app
|
||||||
When I press "Set a reminder for \"Assignment 01\" (Due)" in the app
|
When I press "Set a reminder for \"Assignment 01\" (Due)" in the app
|
||||||
Then I should find "Reminder set for " in the app
|
Then I should find "Reminder set for" in the app
|
||||||
When I press "Delete reminder" in the app
|
When I press "Delete reminder" in the app
|
||||||
Then I should find "Reminder deleted" in the app
|
Then I should find "Reminder deleted" in the app
|
||||||
When I wait "50" seconds
|
When I wait "50" seconds
|
||||||
|
|
|
@ -12,34 +12,33 @@ Feature: Set a new reminder on course
|
||||||
| user | course | role |
|
| user | course | role |
|
||||||
| student1 | C1 | student |
|
| student1 | C1 | student |
|
||||||
|
|
||||||
@ionic7_failure
|
|
||||||
Scenario: Add, delete and update reminder on course
|
Scenario: Add, delete and update reminder on course
|
||||||
Given I entered the course "Course 1" as "student1" in the app
|
Given I entered the course "Course 1" as "student1" in the app
|
||||||
And I press "Course summary" in the app
|
And I press "Course summary" in the app
|
||||||
|
|
||||||
Then I should not find "Set a reminder for \"Course 1\" (Course start date)" in the app
|
Then I should not find "Set a reminder for \"Course 1\" (Course start date)" in the app
|
||||||
And I should find "Set a reminder for \"Course 1\" (Course end date)" in the app
|
And I should not find "Reminder set for" in the app
|
||||||
And "Set a reminder for \"Course 1\" (Course end date)" should not be selected in the app
|
But I should find "Set a reminder for \"Course 1\" (Course end date)" in the app
|
||||||
|
|
||||||
# Default set
|
# Default set
|
||||||
When I press "Set a reminder for \"Course 1\" (Course end date)" in the app
|
When I press "Set a reminder for \"Course 1\" (Course end date)" in the app
|
||||||
Then I should find "Reminder set for " in the app
|
Then I should find "Reminder set for " in the app
|
||||||
And "Set a reminder for \"Course 1\" (Course end date)" should be selected in the app
|
And I should find "Reminder set for" in the app
|
||||||
|
|
||||||
# Set from list
|
# Set from list
|
||||||
When I press "Set a reminder for \"Course 1\" (Course end date)" in the app
|
When I press "Set a reminder for \"Course 1\" (Course end date)" in the app
|
||||||
Then I should find "Set a reminder" in the app
|
Then I should find "Set a reminder" in the app
|
||||||
And "At the time of the event" should be selected in the app
|
And "At the time of the event" should be selected in the app
|
||||||
And "12 hours before" should not be selected in the app
|
But "12 hours before" should not be selected in the app
|
||||||
When I press "12 hours before" in the app
|
When I press "12 hours before" in the app
|
||||||
Then I should find "Reminder set for " in the app
|
Then I should find "Reminder set for " in the app
|
||||||
And "Set a reminder for \"Course 1\" (Course end date)" should be selected in the app
|
And I should find "Reminder set for" in the app
|
||||||
|
|
||||||
# Custom set
|
# Custom set
|
||||||
When I press "Set a reminder for \"Course 1\" (Course end date)" in the app
|
When I press "Set a reminder for \"Course 1\" (Course end date)" in the app
|
||||||
Then I should find "Set a reminder" in the app
|
Then I should find "Set a reminder" in the app
|
||||||
And "At the time of the event" should not be selected in the app
|
And "At the time of the event" should not be selected in the app
|
||||||
And "12 hours before" should be selected in the app
|
But "12 hours before" should be selected in the app
|
||||||
When I press "Custom..." in the app
|
When I press "Custom..." in the app
|
||||||
Then I should find "Custom reminder" in the app
|
Then I should find "Custom reminder" in the app
|
||||||
When I set the following fields to these values in the app:
|
When I set the following fields to these values in the app:
|
||||||
|
@ -47,11 +46,11 @@ Feature: Set a new reminder on course
|
||||||
| Units | hours |
|
| Units | hours |
|
||||||
And I press "Set reminder" in the app
|
And I press "Set reminder" in the app
|
||||||
Then I should find "Reminder set for " in the app
|
Then I should find "Reminder set for " in the app
|
||||||
And "Set a reminder for \"Course 1\" (Course end date)" should be selected in the app
|
And I should find "Reminder set for" in the app
|
||||||
|
|
||||||
# Remove
|
# Remove
|
||||||
When I press "Set a reminder for \"Course 1\" (Course end date)" in the app
|
When I press "Set a reminder for \"Course 1\" (Course end date)" in the app
|
||||||
Then "2 hours before" should be selected in the app
|
Then "2 hours before" should be selected in the app
|
||||||
When I press "Delete reminder" in the app
|
When I press "Delete reminder" in the app
|
||||||
Then I should find "Reminder deleted" in the app
|
Then I should find "Reminder deleted" in the app
|
||||||
And "Set a reminder for \"Course 1\" (Course end date)" should not be selected in the app
|
But I should not find "Reminder set for" in the app
|
||||||
|
|
|
@ -276,7 +276,7 @@ export class TestingBehatDomUtilsService {
|
||||||
/**
|
/**
|
||||||
* Given a list of elements, get the top ancestors among all of them.
|
* Given a list of elements, get the top ancestors among all of them.
|
||||||
*
|
*
|
||||||
* This will remote duplicates and drop any elements nested within each other.
|
* This will remove duplicates and drop any elements nested within each other.
|
||||||
*
|
*
|
||||||
* @param elements Elements list.
|
* @param elements Elements list.
|
||||||
* @returns Top ancestors.
|
* @returns Top ancestors.
|
||||||
|
@ -480,6 +480,34 @@ export class TestingBehatDomUtilsService {
|
||||||
return this.findElementsBasedOnText(locator, options)[0];
|
return this.findElementsBasedOnText(locator, options)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait until an element with the given selector is found.
|
||||||
|
*
|
||||||
|
* @param selector Element selector.
|
||||||
|
* @param timeout Timeout after which an error is thrown.
|
||||||
|
* @param retryFrequency Frequency for retries when the element is not found.
|
||||||
|
* @returns Element.
|
||||||
|
*/
|
||||||
|
async waitForElement<T extends HTMLElement = HTMLElement>(
|
||||||
|
selector: string,
|
||||||
|
timeout: number = 2000,
|
||||||
|
retryFrequency: number = 100,
|
||||||
|
): Promise<T> {
|
||||||
|
const element = document.querySelector<T>(selector);
|
||||||
|
|
||||||
|
if (!element) {
|
||||||
|
if (timeout < retryFrequency) {
|
||||||
|
throw new Error(`Element with '${selector}' selector not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await new Promise(resolve => setTimeout(resolve, retryFrequency));
|
||||||
|
|
||||||
|
return this.waitForElement<T>(selector, timeout - retryFrequency, retryFrequency);
|
||||||
|
}
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to find elements based on their text or Aria label.
|
* Function to find elements based on their text or Aria label.
|
||||||
*
|
*
|
||||||
|
@ -515,7 +543,7 @@ export class TestingBehatDomUtilsService {
|
||||||
protected findElementsBasedOnTextInContainer(
|
protected findElementsBasedOnTextInContainer(
|
||||||
locator: TestingBehatElementLocator,
|
locator: TestingBehatElementLocator,
|
||||||
topContainer: HTMLElement,
|
topContainer: HTMLElement,
|
||||||
options: TestingBehatFindOptions,
|
options: TestingBehatFindOptions = {},
|
||||||
): HTMLElement[] {
|
): HTMLElement[] {
|
||||||
let container: HTMLElement | null = topContainer;
|
let container: HTMLElement | null = topContainer;
|
||||||
|
|
||||||
|
@ -667,37 +695,26 @@ export class TestingBehatDomUtilsService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set an element value.
|
* Set an input element value.
|
||||||
*
|
*
|
||||||
* @param element HTML to set.
|
* @param element Input element.
|
||||||
* @param value Value to be set.
|
* @param value Value.
|
||||||
*/
|
*/
|
||||||
async setElementValue(element: HTMLInputElement | HTMLElement, value: string): Promise<void> {
|
async setInputValue(element: HTMLInputElement | HTMLElement, value: string): Promise<void> {
|
||||||
await NgZone.run(async () => {
|
await NgZone.run(async () => {
|
||||||
const promise = new CorePromisedValue<void>();
|
|
||||||
|
|
||||||
// Functions to get/set value depending on field type.
|
// Functions to get/set value depending on field type.
|
||||||
const setValue = (text: string) => {
|
const setValue = async (text: string) => {
|
||||||
if (! ('value' in element)) {
|
|
||||||
element.innerHTML = text;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element.tagName === 'ION-SELECT') {
|
if (element.tagName === 'ION-SELECT') {
|
||||||
value = value.trim();
|
this.setIonSelectInputValue(element, value);
|
||||||
const optionValue = Array.from(element.querySelectorAll('ion-select-option'))
|
} else if ('value' in element) {
|
||||||
.find((option) => option.innerHTML.trim() === value);
|
|
||||||
|
|
||||||
if (optionValue) {
|
|
||||||
element.value = optionValue.value;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
element.value = text;
|
element.value = text;
|
||||||
|
} else {
|
||||||
|
element.innerHTML = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
element.dispatchEvent(new Event('ionChange'));
|
element.dispatchEvent(new Event('ionChange'));
|
||||||
};
|
};
|
||||||
|
|
||||||
const getValue = () => {
|
const getValue = () => {
|
||||||
if ('value' in element) {
|
if ('value' in element) {
|
||||||
return element.value;
|
return element.value;
|
||||||
|
@ -707,38 +724,79 @@ export class TestingBehatDomUtilsService {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Pretend we have cut and pasted the new text.
|
// Pretend we have cut and pasted the new text.
|
||||||
let event: InputEvent;
|
if (element.tagName !== 'ION-SELECT' && getValue() !== '') {
|
||||||
if (getValue() !== '') {
|
await CoreUtils.nextTick();
|
||||||
event = new InputEvent('input', {
|
await setValue('');
|
||||||
|
|
||||||
|
element.dispatchEvent(new InputEvent('input', {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
view: window,
|
view: window,
|
||||||
cancelable: true,
|
cancelable: true,
|
||||||
inputType: 'deleteByCut',
|
inputType: 'deleteByCut',
|
||||||
});
|
}));
|
||||||
|
|
||||||
await CoreUtils.nextTick();
|
|
||||||
setValue('');
|
|
||||||
element.dispatchEvent(event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value !== '') {
|
if (value !== '') {
|
||||||
event = new InputEvent('input', {
|
await CoreUtils.nextTick();
|
||||||
|
await setValue(value);
|
||||||
|
|
||||||
|
element.dispatchEvent(new InputEvent('input', {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
view: window,
|
view: window,
|
||||||
cancelable: true,
|
cancelable: true,
|
||||||
inputType: 'insertFromPaste',
|
inputType: 'insertFromPaste',
|
||||||
data: value,
|
data: value,
|
||||||
});
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
await CoreUtils.nextTick();
|
/**
|
||||||
setValue(value);
|
* Select an option in an ion-select element.
|
||||||
element.dispatchEvent(event);
|
*
|
||||||
|
* @param element IonSelect element.
|
||||||
|
* @param value Value.
|
||||||
|
*/
|
||||||
|
protected async setIonSelectInputValue(element: HTMLElement, value: string): Promise<void> {
|
||||||
|
// Press select.
|
||||||
|
await TestingBehatDomUtils.pressElement(element);
|
||||||
|
|
||||||
|
// Press option.
|
||||||
|
type IonSelectInterface = 'alert' | 'action-sheet' | 'popover';
|
||||||
|
const selectInterface = element.getAttribute('interface') as IonSelectInterface ?? 'alert';
|
||||||
|
const containerSelector = ({
|
||||||
|
'alert': 'ion-alert.select-alert',
|
||||||
|
'action-sheet': 'ion-action-sheet.select-action-sheet',
|
||||||
|
'popover': 'ion-popover.select-popover',
|
||||||
|
})[selectInterface];
|
||||||
|
const optionSelector = ({
|
||||||
|
'alert': 'button',
|
||||||
|
'action-sheet': 'button',
|
||||||
|
'popover': 'ion-radio',
|
||||||
|
})[selectInterface] ?? '';
|
||||||
|
const optionsContainer = await TestingBehatDomUtils.waitForElement(containerSelector);
|
||||||
|
const options = this.findElementsBasedOnTextInContainer(
|
||||||
|
{ text: value, selector: optionSelector },
|
||||||
|
optionsContainer,
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (options.length === 0) {
|
||||||
|
throw new Error('Couldn\'t find ion-select option.');
|
||||||
|
}
|
||||||
|
|
||||||
|
await TestingBehatDomUtils.pressElement(options[0]);
|
||||||
|
|
||||||
|
// Press options submit.
|
||||||
|
if (selectInterface === 'alert') {
|
||||||
|
const submitButton = optionsContainer.querySelector<HTMLElement>('.alert-button-group button:last-child');
|
||||||
|
|
||||||
|
if (!submitButton) {
|
||||||
|
throw new Error('Couldn\'t find ion-select submit button.');
|
||||||
}
|
}
|
||||||
|
|
||||||
promise.resolve();
|
await TestingBehatDomUtils.pressElement(submitButton);
|
||||||
|
}
|
||||||
return promise;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { TestingBehatDomUtils } from './behat-dom';
|
import { TestingBehatDomUtils, TestingBehatDomUtilsService } from './behat-dom';
|
||||||
import { TestingBehatBlocking } from './behat-blocking';
|
import { TestingBehatBlocking } from './behat-blocking';
|
||||||
import { CoreCustomURLSchemes, CoreCustomURLSchemesProvider } from '@services/urlschemes';
|
import { CoreCustomURLSchemes, CoreCustomURLSchemesProvider } from '@services/urlschemes';
|
||||||
import { ONBOARDING_DONE } from '@features/login/constants';
|
import { ONBOARDING_DONE } from '@features/login/constants';
|
||||||
|
@ -63,6 +63,10 @@ export class TestingBehatRuntimeService {
|
||||||
return CoreNavigator.instance;
|
return CoreNavigator.instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get domUtils(): TestingBehatDomUtilsService {
|
||||||
|
return TestingBehatDomUtils.instance;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init behat functions and set options like skipping onboarding.
|
* Init behat functions and set options like skipping onboarding.
|
||||||
*
|
*
|
||||||
|
@ -468,11 +472,22 @@ export class TestingBehatRuntimeService {
|
||||||
?? options.find(option => option.text === value)?.value
|
?? options.find(option => option.text === value)?.value
|
||||||
?? options.find(option => option.text.includes(value))?.value
|
?? options.find(option => option.text.includes(value))?.value
|
||||||
?? value;
|
?? value;
|
||||||
|
} else if (input.tagName === 'ION-SELECT') {
|
||||||
|
const options = Array.from(input.querySelectorAll('ion-select-option'));
|
||||||
|
|
||||||
|
value = options.find(option => option.value?.toString() === value)?.textContent?.trim()
|
||||||
|
?? options.find(option => option.textContent?.trim() === value)?.textContent?.trim()
|
||||||
|
?? options.find(option => option.textContent?.includes(value))?.textContent?.trim()
|
||||||
|
?? value;
|
||||||
}
|
}
|
||||||
|
|
||||||
await TestingBehatDomUtils.setElementValue(input, value);
|
try {
|
||||||
|
await TestingBehatDomUtils.setInputValue(input, value);
|
||||||
|
|
||||||
return 'OK';
|
return 'OK';
|
||||||
|
} catch (error) {
|
||||||
|
return `ERROR: ${error.message ?? 'Unknown error'}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue