public void CanCaptureReferencesToDynamicallyAddedComponents() { var appElement = MountTestComponent <ComponentRefComponent>(); var incrementButtonSelector = By.CssSelector("#child-component button"); var currentCountTextSelector = By.CssSelector("#child-component p:first-of-type"); var resetButton = appElement.FindElement(By.Id("reset-child")); var toggleChildCheckbox = appElement.FindElement(By.Id("toggle-child")); Func <string> currentCountText = () => appElement.FindElement(currentCountTextSelector).Text; // Verify the reference was captured initially appElement.FindElement(incrementButtonSelector).Click(); WaitAssert.Equal("Current count: 1", currentCountText); resetButton.Click(); WaitAssert.Equal("Current count: 0", currentCountText); appElement.FindElement(incrementButtonSelector).Click(); WaitAssert.Equal("Current count: 1", currentCountText); // Remove and re-add a new instance of the child, checking the text was reset toggleChildCheckbox.Click(); WaitAssert.Empty(() => appElement.FindElements(incrementButtonSelector)); toggleChildCheckbox.Click(); WaitAssert.Equal("Current count: 0", currentCountText); // Verify we have a new working reference appElement.FindElement(incrementButtonSelector).Click(); WaitAssert.Equal("Current count: 1", currentCountText); resetButton.Click(); WaitAssert.Equal("Current count: 0", currentCountText); }
public void InputNumberInteractsWithEditContext_NonNullableInt() { var appElement = MountTestComponent <TypicalValidationComponent>(); var ageInput = appElement.FindElement(By.ClassName("age")).FindElement(By.TagName("input")); var messagesAccessor = CreateValidationMessagesAccessor(appElement); // Validates on edit WaitAssert.Equal("valid", () => ageInput.GetAttribute("class")); ageInput.SendKeys("123\t"); WaitAssert.Equal("modified valid", () => ageInput.GetAttribute("class")); // Can become invalid ageInput.SendKeys("e100\t"); WaitAssert.Equal("modified invalid", () => ageInput.GetAttribute("class")); WaitAssert.Equal(new[] { "The AgeInYears field must be a number." }, messagesAccessor); // Empty is invalid, because it's not a nullable int ageInput.Clear(); ageInput.SendKeys("\t"); WaitAssert.Equal("modified invalid", () => ageInput.GetAttribute("class")); WaitAssert.Equal(new[] { "The AgeInYears field must be a number." }, messagesAccessor); // Zero is within the allowed range ageInput.SendKeys("0\t"); WaitAssert.Equal("modified valid", () => ageInput.GetAttribute("class")); WaitAssert.Empty(messagesAccessor); }
public async Task EditFormWorksWithDataAnnotationsValidator() { var appElement = MountTestComponent <SimpleValidationComponent>(); var userNameInput = appElement.FindElement(By.ClassName("user-name")).FindElement(By.TagName("input")); var acceptsTermsInput = appElement.FindElement(By.ClassName("accepts-terms")).FindElement(By.TagName("input")); var submitButton = appElement.FindElement(By.TagName("button")); var messagesAccessor = CreateValidationMessagesAccessor(appElement); // Editing a field doesn't trigger validation on its own userNameInput.SendKeys("Bert\t"); acceptsTermsInput.Click(); // Accept terms acceptsTermsInput.Click(); // Un-accept terms await Task.Delay(500); // There's no expected change to the UI, so just wait a moment before asserting WaitAssert.Empty(messagesAccessor); Assert.Empty(appElement.FindElements(By.Id("last-callback"))); // Submitting the form does validate submitButton.Click(); WaitAssert.Equal(new[] { "You must accept the terms" }, messagesAccessor); WaitAssert.Equal("OnInvalidSubmit", () => appElement.FindElement(By.Id("last-callback")).Text); // Can make another field invalid userNameInput.Clear(); submitButton.Click(); WaitAssert.Equal(new[] { "Please choose a username", "You must accept the terms" }, messagesAccessor); WaitAssert.Equal("OnInvalidSubmit", () => appElement.FindElement(By.Id("last-callback")).Text); // Can make valid userNameInput.SendKeys("Bert\t"); acceptsTermsInput.Click(); submitButton.Click(); WaitAssert.Empty(messagesAccessor); WaitAssert.Equal("OnValidSubmit", () => appElement.FindElement(By.Id("last-callback")).Text); }
public void ValidationMessageDisplaysMessagesForField() { var appElement = MountTestComponent <TypicalValidationComponent>(); var emailContainer = appElement.FindElement(By.ClassName("email")); var emailInput = emailContainer.FindElement(By.TagName("input")); var emailMessagesAccessor = CreateValidationMessagesAccessor(emailContainer); var submitButton = appElement.FindElement(By.TagName("button")); // Doesn't show messages for other fields submitButton.Click(); WaitAssert.Empty(emailMessagesAccessor); // Updates on edit emailInput.SendKeys("abc\t"); WaitAssert.Equal(new[] { "That doesn't look like a real email address" }, emailMessagesAccessor); // Can show more than one message emailInput.SendKeys("too long too long too long\t"); WaitAssert.Equal(new[] { "That doesn't look like a real email address", "We only accept very short email addresses (max 10 chars)" }, emailMessagesAccessor); // Can become valid emailInput.Clear(); emailInput.SendKeys("[email protected]\t"); WaitAssert.Empty(emailMessagesAccessor); }
public void InputDateInteractsWithEditContext_NonNullableDateTime() { var appElement = MountTestComponent <TypicalValidationComponent>(); var renewalDateInput = appElement.FindElement(By.ClassName("renewal-date")).FindElement(By.TagName("input")); var messagesAccessor = CreateValidationMessagesAccessor(appElement); // Validates on edit WaitAssert.Equal("valid", () => renewalDateInput.GetAttribute("class")); renewalDateInput.SendKeys("01/01/2000\t"); WaitAssert.Equal("modified valid", () => renewalDateInput.GetAttribute("class")); // Can become invalid renewalDateInput.SendKeys("0/0/0"); WaitAssert.Equal("modified invalid", () => renewalDateInput.GetAttribute("class")); WaitAssert.Equal(new[] { "The RenewalDate field must be a date." }, messagesAccessor); // Empty is invalid, because it's not nullable renewalDateInput.SendKeys($"{Keys.Backspace}\t{Keys.Backspace}\t{Keys.Backspace}\t"); WaitAssert.Equal("modified invalid", () => renewalDateInput.GetAttribute("class")); WaitAssert.Equal(new[] { "The RenewalDate field must be a date." }, messagesAccessor); // Can become valid renewalDateInput.SendKeys("01/01/01\t"); WaitAssert.Equal("modified valid", () => renewalDateInput.GetAttribute("class")); WaitAssert.Empty(messagesAccessor); }
public void NonBubblingEvent_FiredOnElementWithoutHandler() { Browser.FindElement(By.Id("input-without-onfocus")).Click(); // Triggers no event WaitAssert.Empty(GetLogLines); }
public void CanRenderFragmentsWhilePreservingSurroundingElements() { // Initially, the region isn't shown var appElement = MountTestComponent <RenderFragmentToggler>(); var originalButton = appElement.FindElement(By.TagName("button")); Func <IEnumerable <IWebElement> > fragmentElements = () => appElement.FindElements(By.CssSelector("p[name=fragment-element]")); Assert.Empty(fragmentElements()); // The JS-side DOM builder handles regions correctly, placing elements // after the region after the corresponding elements Assert.Equal("The end", appElement.FindElements(By.CssSelector("div > *:last-child")).Single().Text); // When we click the button, the region is shown originalButton.Click(); WaitAssert.Single(fragmentElements); // The button itself was preserved, so we can click it again and see the effect originalButton.Click(); WaitAssert.Empty(fragmentElements); }
public void InputTextInteractsWithEditContext() { var appElement = MountTestComponent <TypicalValidationComponent>(); var nameInput = appElement.FindElement(By.ClassName("name")).FindElement(By.TagName("input")); var messagesAccessor = CreateValidationMessagesAccessor(appElement); // Validates on edit WaitAssert.Equal("valid", () => nameInput.GetAttribute("class")); nameInput.SendKeys("Bert\t"); WaitAssert.Equal("modified valid", () => nameInput.GetAttribute("class")); // Can become invalid nameInput.SendKeys("01234567890123456789\t"); WaitAssert.Equal("modified invalid", () => nameInput.GetAttribute("class")); WaitAssert.Equal(new[] { "That name is too long" }, messagesAccessor); // Can become valid nameInput.Clear(); nameInput.SendKeys("Bert\t"); WaitAssert.Equal("modified valid", () => nameInput.GetAttribute("class")); WaitAssert.Empty(messagesAccessor); }
public void InputTextAreaInteractsWithEditContext() { var appElement = MountTestComponent <TypicalValidationComponent>(); var descriptionInput = appElement.FindElement(By.ClassName("description")).FindElement(By.TagName("textarea")); var messagesAccessor = CreateValidationMessagesAccessor(appElement); // Validates on edit WaitAssert.Equal("valid", () => descriptionInput.GetAttribute("class")); descriptionInput.SendKeys("Hello\t"); WaitAssert.Equal("modified valid", () => descriptionInput.GetAttribute("class")); // Can become invalid descriptionInput.SendKeys("too long too long too long too long too long\t"); WaitAssert.Equal("modified invalid", () => descriptionInput.GetAttribute("class")); WaitAssert.Equal(new[] { "Description is max 20 chars" }, messagesAccessor); // Can become valid descriptionInput.Clear(); descriptionInput.SendKeys("Hello\t"); WaitAssert.Equal("modified valid", () => descriptionInput.GetAttribute("class")); WaitAssert.Empty(messagesAccessor); }
public void InputNumberInteractsWithEditContext_NullableFloat() { var appElement = MountTestComponent <TypicalValidationComponent>(); var heightInput = appElement.FindElement(By.ClassName("height")).FindElement(By.TagName("input")); var messagesAccessor = CreateValidationMessagesAccessor(appElement); // Validates on edit WaitAssert.Equal("valid", () => heightInput.GetAttribute("class")); heightInput.SendKeys("123.456\t"); WaitAssert.Equal("modified valid", () => heightInput.GetAttribute("class")); // Can become invalid heightInput.SendKeys("e100\t"); WaitAssert.Equal("modified invalid", () => heightInput.GetAttribute("class")); WaitAssert.Equal(new[] { "The OptionalHeight field must be a number." }, messagesAccessor); // Empty is valid, because it's a nullable float heightInput.Clear(); heightInput.SendKeys("\t"); WaitAssert.Equal("modified valid", () => heightInput.GetAttribute("class")); WaitAssert.Empty(messagesAccessor); }
public void CanCaptureReferencesToDynamicallyAddedElements() { var appElement = MountTestComponent <ElementRefComponent>(); var buttonElement = appElement.FindElement(By.TagName("button")); var checkbox = appElement.FindElement(By.CssSelector("input[type=checkbox]")); // We're going to remove the input. But first, put in some contents // so we can observe it's not the same instance later appElement.FindElement(By.Id("capturedElement")).SendKeys("some text"); // Remove the captured element checkbox.Click(); WaitAssert.Empty(() => appElement.FindElements(By.Id("capturedElement"))); // Re-add it; observe it starts empty again checkbox.Click(); var inputElement = appElement.FindElement(By.Id("capturedElement")); Assert.Equal(string.Empty, inputElement.GetAttribute("value")); // See that the capture variable was automatically updated to reference the new instance buttonElement.Click(); WaitAssert.Equal("Clicks: 1", () => inputElement.GetAttribute("value")); }
public void CanAddAndRemoveEventHandlersDynamically() { var appElement = MountTestComponent <CounterComponent>(); var countDisplayElement = appElement.FindElement(By.TagName("p")); var incrementButton = appElement.FindElement(By.TagName("button")); var toggleClickHandlerCheckbox = appElement.FindElement(By.CssSelector("[type=checkbox]")); // Initial count is zero; clicking button increments count Assert.Equal("Current count: 0", countDisplayElement.Text); incrementButton.Click(); WaitAssert.Equal("Current count: 1", () => countDisplayElement.Text); // We can remove an event handler toggleClickHandlerCheckbox.Click(); WaitAssert.Empty(() => appElement.FindElements(By.Id("listening-message"))); incrementButton.Click(); WaitAssert.Equal("Current count: 1", () => countDisplayElement.Text); // We can add an event handler toggleClickHandlerCheckbox.Click(); appElement.FindElement(By.Id("listening-message")); incrementButton.Click(); WaitAssert.Equal("Current count: 2", () => countDisplayElement.Text); }