23

I'm trying to write a script that needs to adapt it's workflow behavior depending on whether a particular browser object found by CSS selector exists or does not exist.

I do not want to use a document.getElementByID method as this is not technically a CSS selector, and our entire enterprise is standardized on CSS selector so anything that walks the DOM other then a CSS selector won't make it past our code review process anyway.

var thing = await things.thingSelector(thingName);
if (await t.expect(thing.exists).notOk()) {
   await t.click(things.OpenThing(thingName));
} else {
   return false;
}
return true;

Where thingSelector is:

const thingSelector = name =>
  Selector('p.thing-header-title span')
    .withText(name)
    .parent('div.thing');

Where OpenThing is:

const OpenThing = name =>
    thingSelector(name)
        .find('a.thing-footer-item')
        .withText('Open');

I need to be able to continue execution if the object is not there and I'm checking that it exists, or if the object is there and I'm checking that it does not exist, and also the cases where the object is not there and it does not exist and the object is not there and I'm checking that it does not exist.

In all cases I still need to proceed with the workflow.

I've tried both sides of the logic coin:

if (!await t.expect(thing.exists).ok())

And

if (await t.expect(thing.exists).notOk())

If one of the above doesn't fail in one scenario it will fail in the other, and the other one will fail in the scenario that the first one didn't fail. I need something that will give me the logic, but not ever fail the script execution and still allow me to return either True or False depending on if the object is present or not present.

Thank you in advance for helping me to solve this problem, and also to learn and grow in my Javascript skills!

Seth Eden
  • 1,142
  • 2
  • 20
  • 42
  • 1
    What do you mean "fail the script execution"? If you get an error all its details should go in the question. Also, given `await` does not return after a rejected promise, it would help to know how and if `t.expect(thing.exists).notOk())` can become rejected. – traktor Nov 17 '17 at 22:29

4 Answers4

31

You can check the async exists property in the if condition in the following way:

if(await things.thingSelector(thingName).exists) {
    // do something 
} 
Alexander Moskovkin
  • 1,861
  • 12
  • 13
  • 6
    Thank you so much! I understand now a little better how it's supposed to work. This worked!! :-D I love learning! – Seth Eden Nov 20 '17 at 18:33
  • 4
    False-negatives may occur because the test driver will immediately resolve this promise if the element does not exist (yet). That is to say: if you are, for instance, clicking a button and expeting the element to appear, but during evaluation of the if-clause the element has not been rendered yet, than the clause will evaluate to false. If evaluation would take place only a moment later, it would return true. – Samuel Dec 13 '18 at 16:00
  • @Samuel I think the timeout mechanism caters for this. and you could explicitly specify how much time that is – sduduzo gumede Sep 01 '19 at 10:46
9

You can use the following assertions to test existence and non-existence elements:

test('Test existence and non-existence elements', async t => {
    await t
        .expect(Selector('#existing-element').exists)
        .expect(Selector('#non-existing-element').exists).notOk()
});
Mauricio Sánchez
  • 4,602
  • 1
  • 23
  • 15
  • 2
    I used this sample. In my first attempt, my tests failed with follow error msg: `ReferenceError: Selector is not defined`. Than I imported it in my test file like this: `import { Selector } from 'testcafe';`. After running again the test it fails again with a new msg: `An assertion method is not specified`. Any idea how to fix this? – webta.st.ic Jun 28 '19 at 10:17
  • 3
    I managed it: For the `true` case, you have also to add `.ok()` like this -> `.expect(Selector('#existing-element').exists).ok()` without the `.ok()` it failed in my case. – webta.st.ic Jun 28 '19 at 11:23
  • Doesn't really help if you need an if-condition like clicking a re-sizable toolbar with a fly-out menu that is resized with the window size. Depending on the window size, the menu item you are looking for may or not be in the toolbar, or it could be in the fly-out menu. The fly-out menu might not even be defined in the DOM body which means checking for it's existence would fail the script since it's not even found in the DOM. But once you click the fly-out menu it would load and can be found. This is the difficulty I am actually facing now! :-D – Seth Eden Jun 28 '19 at 13:13
  • This really helped me, exactly what I was looking for. Mixed with @webta.st.ic advice for the .ok(). – Daniel Oct 21 '21 at 21:34
1
  • How to check if an element exists:

      test('Element with id "element" exists', async t => {
      await t.expect(Selector('#element').exists).ok(); });
    
  • How to check if an element does NOT exist:

     test('Element with id "element" shouldn\'t exist', async t => {
     await t.expect(Selector('#element').exists).notOk(); });
    

Check out the official documentation.

AlexxBoro
  • 329
  • 5
  • 3
0

this is working for me, you can give it a try

async veriryCreativeIconButtonNotExists(){
await t.expect(this.exportButton.exists).ok()
await t.expect(this.columnPickerIcon.exists).ok()
await t.expect(this.filterColumnIcon.exists).ok()
if (await t.expect(this.columnPickerIcon.exists).ok()){
  await t.expect(this.creavtiveIconButton.exists).ok()
  await t.click(this.creavtiveIconButton)
  await t.expect(this.creativeImage.exists).ok()
  await t.click(this.creativeImage)
} else {
  return false;
}
return true;
surender pal
  • 447
  • 6
  • 15