kif-framework / KIF

Keep It Functional - An iOS Functional Testing Framework
Other
6.21k stars 912 forks source link

iOS7: Failed to find key for character "P" #263

Closed plu closed 9 years ago

plu commented 10 years ago

Hi,

on KIF 2.0.0 sometimes I get this error message: Failed to find key for character "P". The problem is, that it is happening randomly. The failing character changes randomly too. I can't pin it down to one test case either. Neither can I see any other pattern. But what I can tell is:

Maybe somebody has an idea what could be the cause?

Thanks, plu

bnickel commented 10 years ago

That's really strange, I have never seen anything like it. Are you switching between keyboards, entering into a non-text field, etc?

plu commented 10 years ago

We're not switching keyboards or entering it in a non-text field. All our input fields are standard controls. Yesterday I spotted one place in our code/testsuite, where we have a huge UITableView having around 3000 entries. This tableView is connected to a UISearchBar. The search/core data operation seems to block the main thread quite some time (around 1 second). I suspect this to be the root cause for KIF not being able to type on the keyboard properly. I'll keep you posted once I find out some more information.

MattNewberry commented 10 years ago

I've seen this as well - I'm currently writing tests for entering text into a simple form and in addition to the "Failed to find key..." error, I'm also seeing the wrong characters being entered into the field.

bnickel commented 10 years ago

Can you provide more details on your system, what environment the tests are running in, how the characters being entered are wrong, what string you were trying to enter?

pietbrauer commented 10 years ago

Hi,

I am part of @plu team.

I attach some images made by our machines.

We are using Jenkins and the iOS 7 simulator.

  1. It types wrong uppercased letters xngkiftestcasebirthday m line 162
  2. It should type 'Iphone Basic English' xngkiftestcasemessages m line 173
  3. It should type 'Iphone Basic English' xngkiftestcasemessages m line 191
  4. It should type 'Iphone Basic English' xngkiftestcasemessages m line 217

The last failures seem to happen on a regular basis.

bnickel commented 10 years ago

I literally cannot make this happen. Is it literally jumping to the symbol plane and hitting "!"? It look like "B" and "!" are in the same spot, so something fishy is happening.

I set my keyboard to German (Germany) and ran the following test, flawlessly.

- (void)testIssue263
{
    [tester enterText:@"Iphone Basic English" intoViewWithAccessibilityLabel:@"Other Text" traits:UIAccessibilityTraitNone expectedResult:@"IPhone Basic English"];
    [tester clearTextFromAndThenEnterText:@"GebCJC Äxing" intoViewWithAccessibilityLabel:@"Other Text"];
}

Per @plu's above comment, I tried blocking the main thread on input as well:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    sleep(1);
    return YES;
}

Still worked perfectly.

neonichu commented 10 years ago

I am seeing a somewhat related problem. In some cases, entering strings into text-fields leads to the first, or much more rarely the last, character missing.

My mitigation is something like this:

[textField becomeFirstResponder];
[self waitForViewWithAccessibilityLabel:@"a"];

Any new ideas on this?

phatmann commented 10 years ago

I am seeing mistyped characters when running on the iPad simulator under iOS 6.1. The first character is supposed to be an "s" but always ends up as an "i". I cannot reproduce this in the KIF test suite, so there is something about my app that is causing this issue. The issue can be reproduced on other developer's machines and on Xcode server, so it is not related to my environment.

I traced through the KIF code, and it is correctly finding the "s" key and the frame rect is correct. However, the taps ends up on the "i" key, which is of course nowhere near it. I am quite baffled by this!

Some of the problems in this thread seem to be caused by the same issue: the tap on the first key hits the wrong key or no key at all.

I am digging into the problem now. If anyone has any hints or ideas, please let me know.

jeffnuss commented 10 years ago

Well sorry for thrashing this issue with my amended commit messages :-) #366 is my workaround for this issue.

I'm seeing this same error when calling clearTextFromAndThenEnterText:intoViewWithAccessibilityLabel: or enterText:intoViewWithAccessibilityLabel: with any capital letter that isn't the first letter in the string to be entered into the view. The view I'm entering text into is a UISearchBar that is bound to a UITableView with ~340 cells in it. As an example of what I'm talking about,

[tester clearTextFromAndThenEnterText:@"How Firm a Foundation" intoViewWithAccessibilityLabel:@"Search"];

fails on the "F" in "Firm." Watching the test happen, the keyboard seems to flash between each of the different planes before failing. I'm just using the standard english keyboard on the 64-bit simulator on iOS 7.1.

I think @plu is on to something with respect to the search operation blocking the main thread because if I step through _enterCharacter:history: in KIFTypist, the test will pass.

brightredchilli commented 10 years ago

This sounds a little familar to what I was experiencing on #356. Have you guys tried extending the keystroke delay?

plu commented 10 years ago

@brightredchilli yep, see my first post: "Slowing down the text input does not help at all. I've tried to go from 0.05f over 0.10f to 0.20f, but nothing changed. At least not on the virtual machines."

pietbrauer commented 9 years ago

We solved the problem by pasting text instead of typing. It is also a lot faster.

bnickel commented 9 years ago

Closing since we've moved to a different text entry system that should solve this.

ohayon commented 9 years ago

@pietbrauer how are you guys using KIF to paste text??? been on a search for this functionality to no avail.

pietbrauer commented 9 years ago

@ohwutup We are using it like this:

- (void)                 pasteText:(NSString *)text
    intoViewWithAccessibilityLabel:(NSString *)label
                            traits:(UIAccessibilityTraits)traits
                       atBeginning:(BOOL)atBeginning {
    UIView *view = nil;
    UIAccessibilityElement *element = nil;

    if (label) {
        [self waitForAccessibilityElement:&element view:&view withLabel:label value:nil traits:traits tappable:YES];
        [self tapAccessibilityElement:element inView:view];
    }

    // Before we paste text, we need to make sure that the view is firstResponder
    // and does respond to insertText:
    if (![view conformsToProtocol:@protocol(UITextInput)]) {
        UIResponder *firstResponder = [[[UIApplication sharedApplication] keyWindow] firstResponder];
        if ([firstResponder isKindOfClass:[UIView class]]) {
            view = (UIView *)firstResponder;
        }
    }

    if (atBeginning) {
        [self tapUpperLeftCornerOfView:view];
        if ([view isKindOfClass:UITextView.class]) {
            UITextView *tv = (UITextView *)tv;
            tv.selectedRange = NSMakeRange(0, 0);
        }
    }

    NSString *existingText = @"";
    if ([view respondsToSelector:@selector(text)]) {
        existingText = [view performSelector:@selector(text) withObject:nil];
    }
    [self pasteTextIntoCurrentFirstResponder:text fallbackView:view];
}

- (void)pasteTextIntoCurrentFirstResponder:(NSString *)text fallbackView:(UIView *)fallbackView {
    UIView *view = fallbackView;

    if (!view) {
        UIResponder *firstResponder = [[[UIApplication sharedApplication] keyWindow] firstResponder];
        if ([firstResponder isKindOfClass:[UIView class]]) {
            view = (UIView *)firstResponder;
        }
    }

    if ([view conformsToProtocol:@protocol(UITextInput)]) {
        id inputDelegate = ((id<UITextInput>)view).inputDelegate;
        if ([self shouldInsertText:text intoView:view]) {
            [inputDelegate textWillChange:inputDelegate];
            [(id < UITextInput >) view insertText:text];
            [inputDelegate textDidChange:inputDelegate];
        }
    } else {
        [self failWithError:[NSError KIFErrorWithFormat:@"View \"%@\" does not conform to UITextInput protocol:", view] stopTest:YES];
    }
    if ([view isFirstResponder]) {
        [view resignFirstResponder];
    } else {
        [self failWithError:[NSError KIFErrorWithFormat:@"View \"%@\" is not first responder", view] stopTest:YES];
    }
    [self waitForAbsenceOfKeyboard];
}

Might do a Pull Request to add it to KIF if @bnickel agrees?

ohayon commented 9 years ago

@pietbrauer, do you have this in a PR where i can see the full code? missing implementation for -shouldEnterText:intoView: and -tapUpperLeftCornerOfView

pietbrauer commented 9 years ago

Sorry couldn't find shouldEnterText anywhere (also not in the listing I provided). But here is the tapUpperLeftCornerOfView method:

- (void)tapUpperLeftCornerOfView:(UIView *)view {
    CGPoint topLeftCorner = CGPointMake(0, 0);
    CGPoint viewTopLeft = [view convertPoint:topLeftCorner toView:nil];
    [tester tapScreenAtPoint:viewTopLeft];
}