Skip to content

Commit

Permalink
PW Upgrade and improving login (#271)
Browse files Browse the repository at this point in the history
* resolve

* PW version 1.28.0

* unittest fix

* PW 1.33.0

* PW 1.35.0

---------

Co-authored-by: Landon Rogers <[email protected]>
  • Loading branch information
NavneetThekkumpat and landonmsft authored Jun 28, 2023
1 parent 9bb783c commit a42aa21
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 91 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -250,14 +250,14 @@ public async Task SetupNetworkRequestMockAsyncTest()
MockSingleTestInstanceState.Setup(x => x.GetTestSuiteDefinition()).Returns(testSuiteDefinition);
MockFileSystem.Setup(x => x.IsValidFilePath(It.IsAny<string>())).Returns(true);
MockBrowserContext.Setup(x => x.NewPageAsync()).Returns(Task.FromResult(MockPage.Object));
MockPage.Setup(x => x.RouteAsync(mock.RequestURL, It.IsAny<Action<IRoute>>(), It.IsAny<PageRouteOptions>())).Returns(Task.FromResult<IResponse?>(MockResponse.Object));
MockPage.Setup(x => x.RouteAsync(mock.RequestURL, It.IsAny<Func<IRoute, Task>>(), It.IsAny<PageRouteOptions>())).Returns(Task.FromResult<IResponse?>(MockResponse.Object));

var playwrightTestInfraFunctions = new PlaywrightTestInfraFunctions(MockTestState.Object, MockSingleTestInstanceState.Object,
MockFileSystem.Object, browserContext: MockBrowserContext.Object);
await playwrightTestInfraFunctions.SetupNetworkRequestMockAsync();

MockBrowserContext.Verify(x => x.NewPageAsync(), Times.Once);
MockPage.Verify(x => x.RouteAsync(mock.RequestURL, It.IsAny<Action<IRoute>>(), It.IsAny<PageRouteOptions>()), Times.Once);
MockPage.Verify(x => x.RouteAsync(mock.RequestURL, It.IsAny<Func<IRoute, Task>>(), It.IsAny<PageRouteOptions>()), Times.Once);
MockFileSystem.Verify(x => x.IsValidFilePath(mock.ResponseDataFile), Times.Once());
}

Expand Down Expand Up @@ -618,43 +618,98 @@ public async Task RouteNetworkRequestTest()
}

[Fact]
public async Task DisposeAsyncTest()
public async Task HandleUserPasswordScreen()
{
var browserConfig = new BrowserConfiguration()
{
Browser = "Chromium",
Device = null,
ScreenHeight = null,
ScreenWidth = null
};
string testSelector = "input:has-text('Password')";
string testTextEntry = "*****";
string desiredUrl = "https://make.powerapps.com";

var testSettings = new TestSettings()
{
RecordVideo = true,
Timeout = 15
};
MockSingleTestInstanceState.Setup(x => x.GetLogger()).Returns(MockLogger.Object);
LoggingTestHelper.SetupMock(MockLogger);

var mockLocator = new Mock<ILocator>(MockBehavior.Strict);
MockPage.Setup(x => x.Locator(It.IsAny<string>(), null)).Returns(mockLocator.Object);
mockLocator.Setup(x => x.WaitForAsync(null)).Returns(Task.CompletedTask);

MockPage.Setup(x => x.FillAsync(testSelector, testTextEntry, null)).Returns(Task.CompletedTask);
MockPage.Setup(x => x.ClickAsync("input[type=\"submit\"]", null)).Returns(Task.CompletedTask);
// Assume ask already logged in
MockPage.Setup(x => x.WaitForSelectorAsync("[id=\"KmsiCheckboxField\"]", It.IsAny<PageWaitForSelectorOptions>())).Returns(Task.FromResult(MockElementHandle.Object));
// Simulate Click to stay signed in
MockPage.Setup(x => x.ClickAsync("[id=\"idBtn_Back\"]", null)).Returns(Task.CompletedTask);
// Wait until login is complete and redirect to desired page
MockPage.Setup(x => x.WaitForURLAsync(desiredUrl, null)).Returns(Task.CompletedTask);

var playwrightTestInfraFunctions = new PlaywrightTestInfraFunctions(MockTestState.Object, MockSingleTestInstanceState.Object,
MockFileSystem.Object, browserContext: MockBrowserContext.Object, page: MockPage.Object);

await playwrightTestInfraFunctions.HandleUserPasswordScreen(testSelector, testTextEntry, desiredUrl);

MockPage.Verify(x => x.Locator(It.Is<string>(v => v.Equals(testSelector)), null));
MockPage.Verify(x => x.WaitForSelectorAsync("[id=\"KmsiCheckboxField\"]", It.Is<PageWaitForSelectorOptions>(v => v.Timeout >= 8000)));
}

[Fact]
public async Task HandleUserPasswordScreenErrorEntry()
{
string testSelector = "input:has-text('Password')";
string testTextEntry = "*****";
string desiredUrl = "https://make.powerapps.com";

MockSingleTestInstanceState.Setup(x => x.GetBrowserConfig()).Returns(browserConfig);
MockPlaywrightObject.SetupGet(x => x[It.IsAny<string>()]).Returns(MockBrowserType.Object);
MockBrowserType.Setup(x => x.LaunchAsync(It.IsAny<BrowserTypeLaunchOptions>())).Returns(Task.FromResult(MockBrowser.Object));
MockTestState.Setup(x => x.GetTestSettings()).Returns(testSettings);
MockSingleTestInstanceState.Setup(x => x.GetLogger()).Returns(MockLogger.Object);
MockSingleTestInstanceState.Setup(x => x.GetTestResultsDirectory()).Returns("C:\\TestResults");
MockBrowser.Setup(x => x.NewContextAsync(It.IsAny<BrowserNewContextOptions>())).Returns(Task.FromResult(MockBrowserContext.Object));
LoggingTestHelper.SetupMock(MockLogger);

// Mock Dispose methods
MockPlaywrightObject.Setup(x => x.Dispose());
MockBrowserContext.Setup(x => x.DisposeAsync()).Returns(ValueTask.CompletedTask);
var mockLocator = new Mock<ILocator>(MockBehavior.Strict);
MockPage.Setup(x => x.Locator(It.IsAny<string>(), null)).Returns(mockLocator.Object);
mockLocator.Setup(x => x.WaitForAsync(null)).Returns(Task.CompletedTask);

MockPage.Setup(x => x.FillAsync(testSelector, testTextEntry, null)).Returns(Task.CompletedTask);
MockPage.Setup(x => x.ClickAsync("input[type=\"submit\"]", null)).Returns(Task.CompletedTask);
// Not ask to sign in as selector not found
MockPage.Setup(x => x.WaitForSelectorAsync("[id=\"KmsiCheckboxField\"]", It.IsAny<PageWaitForSelectorOptions>())).Throws(new TimeoutException());
// Simulate error response for password error
MockPage.Setup(x => x.WaitForSelectorAsync("[id=\"passwordError\"]", It.IsAny<PageWaitForSelectorOptions>())).Returns(Task.FromResult(MockElementHandle.Object));
// Throw exception as not make it to desired url
MockPage.Setup(x => x.WaitForURLAsync(desiredUrl, null)).Throws(new TimeoutException());

var playwrightTestInfraFunctions = new PlaywrightTestInfraFunctions(MockTestState.Object, MockSingleTestInstanceState.Object,
MockFileSystem.Object, MockPlaywrightObject.Object, MockBrowserContext.Object);
await playwrightTestInfraFunctions.SetupAsync();
MockFileSystem.Object, browserContext: MockBrowserContext.Object, page: MockPage.Object);

await playwrightTestInfraFunctions.DisposeAsync();
await Assert.ThrowsAsync<InvalidOperationException>(async () => await playwrightTestInfraFunctions.HandleUserPasswordScreen(testSelector, testTextEntry, desiredUrl));

MockPlaywrightObject.Verify(x => x.Dispose(), Times.Once());
MockBrowserContext.Verify(x => x.DisposeAsync(), Times.Once());
MockPage.Verify(x => x.Locator(It.Is<string>(v => v.Equals(testSelector)), null));
MockPage.Verify(x => x.WaitForSelectorAsync("[id=\"passwordError\"]", It.Is<PageWaitForSelectorOptions>(v => v.Timeout >= 2000)));
}

[Fact]
public async Task HandleUserPasswordScreenUnknownError()
{
string testSelector = "input:has-text('Password')";
string testTextEntry = "*****";
string desiredUrl = "https://make.powerapps.com";

MockSingleTestInstanceState.Setup(x => x.GetLogger()).Returns(MockLogger.Object);
LoggingTestHelper.SetupMock(MockLogger);
var mockLocator = new Mock<ILocator>(MockBehavior.Strict);
MockPage.Setup(x => x.Locator(It.IsAny<string>(), null)).Returns(mockLocator.Object);
mockLocator.Setup(x => x.WaitForAsync(null)).Returns(Task.CompletedTask);

MockPage.Setup(x => x.FillAsync(testSelector, testTextEntry, null)).Returns(Task.CompletedTask);
MockPage.Setup(x => x.ClickAsync("input[type=\"submit\"]", null)).Returns(Task.CompletedTask);
// Not ask to sign in as selector not found
MockPage.Setup(x => x.WaitForSelectorAsync("[id=\"KmsiCheckboxField\"]", null)).Throws(new TimeoutException());
// Also not able to find password error, must be some other error
MockPage.Setup(x => x.WaitForSelectorAsync("[id=\"passwordError\"]", It.IsAny<PageWaitForSelectorOptions>())).Throws(new TimeoutException());
// Throw exception as not make it to desired url
MockPage.Setup(x => x.WaitForURLAsync(desiredUrl, null)).Throws(new TimeoutException());

var playwrightTestInfraFunctions = new PlaywrightTestInfraFunctions(MockTestState.Object, MockSingleTestInstanceState.Object,
MockFileSystem.Object, browserContext: MockBrowserContext.Object, page: MockPage.Object);

await Assert.ThrowsAsync<TimeoutException>(async () => await playwrightTestInfraFunctions.HandleUserPasswordScreen(testSelector, testTextEntry, desiredUrl));

MockPage.Verify(x => x.Locator(It.Is<string>(v => v.Equals(testSelector)), null));
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Playwright" Version="1.22.0" />
<PackageReference Include="Microsoft.Playwright" Version="1.35.0" />
<PackageReference Include="Microsoft.PowerFx.Interpreter" Version="0.2.3-preview" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="YamlDotNet" Version="11.2.1" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,88 +308,75 @@ public async Task HandleUserEmailScreen(string selector, string value)
await Page.Keyboard.PressAsync("Tab", new KeyboardPressOptions { Delay = 20 });
}

// Justification: Limited ability to run unit tests for
// Playwright actions on the sign-in page
[ExcludeFromCodeCoverage]
public async Task HandleUserPasswordScreen(string selector, string value, string desiredUrl)
{
var logger = _singleTestInstanceState.GetLogger();

// Setting options fot the RunAndWaitForNavigationAsync function
PageRunAndWaitForNavigationOptions options = new PageRunAndWaitForNavigationOptions();

// URL that should be redirected to
options.UrlString = desiredUrl;

ValidatePage();

try
{
// Only continue if redirected to the correct page
await Page.RunAndWaitForNavigationAsync(async () =>
// Find the password box
await Page.Locator(selector).WaitForAsync();

// Fill in the password
await Page.FillAsync(selector, value);

// Submit password form
await this.ClickAsync("input[type=\"submit\"]");

PageWaitForSelectorOptions selectorOptions = new PageWaitForSelectorOptions();
selectorOptions.Timeout = 8000;

// For instances where there is a 'Stay signed in?' dialogue box
try
{
// Find the password box
await Page.Locator(selector).WaitForAsync();
logger.LogDebug("Checking if asked to stay signed in.");

// Fill in the password
await Page.FillAsync(selector, value);
// Check if we received a 'Stay signed in?' box?
await Page.WaitForSelectorAsync("[id=\"KmsiCheckboxField\"]", selectorOptions);
logger.LogDebug("Was asked to 'stay signed in'.");

// Submit password form
await this.ClickAsync("input[type=\"submit\"]");
// Click to stay signed in
await Page.ClickAsync("[id=\"idBtn_Back\"]");
}
// If there is no 'Stay signed in?' box, an exception will throw; just catch and continue
catch (Exception ssiException)
{
logger.LogDebug("Exception encountered: " + ssiException.ToString());

PageWaitForSelectorOptions selectorOptions = new PageWaitForSelectorOptions();
selectorOptions.Timeout = 8000;
// Keep record if passwordError was encountered
bool hasPasswordError = false;

// For instances where there is a 'Stay signed in?' dialogue box
try
{
logger.LogDebug("Checking if asked to stay signed in.");
selectorOptions.Timeout = 2000;

// Check if we received a 'Stay signed in?' box?
await Page.WaitForSelectorAsync("[id=\"KmsiCheckboxField\"]", selectorOptions);
logger.LogDebug("Was asked to 'stay signed in'.");
// Check if we received a password error
await Page.WaitForSelectorAsync("[id=\"passwordError\"]", selectorOptions);
hasPasswordError = true;
}
catch (Exception peException)
{
logger.LogDebug("Exception encountered: " + peException.ToString());
}

// Click to stay signed in
await Page.ClickAsync("[id=\"idBtn_Back\"]");
// If encountered password error, exit program
if (hasPasswordError)
{
logger.LogError("Incorrect password entered. Make sure you are using the correct credentials.");
throw new InvalidOperationException();
}
// If there is no 'Stay signed in?' box, an exception will throw; just catch and continue
catch (Exception ssiException)
// If not, continue
else
{
logger.LogDebug("Exception encountered: " + ssiException.ToString());
// Keep record if passwordError was encountered
bool hasPasswordError = false;
try
{
selectorOptions.Timeout = 2000;
// Check if we received a password error
await Page.WaitForSelectorAsync("[id=\"passwordError\"]", selectorOptions);
hasPasswordError = true;
}
catch (Exception peException)
{
logger.LogDebug("Exception encountered: " + peException.ToString());
}
// If encountered password error, exit program
if (hasPasswordError)
{
logger.LogError("Incorrect password entered. Make sure you are using the correct credentials.");
throw new InvalidOperationException();
}
// If not, continue
else
{
logger.LogDebug("Did not encounter an invalid password error.");
}
logger.LogDebug("Was not asked to 'stay signed in'.");
logger.LogDebug("Did not encounter an invalid password error.");
}

await Page.WaitForLoadStateAsync(LoadState.NetworkIdle);
}, options);
logger.LogDebug("Was not asked to 'stay signed in'.");
}

await Page.WaitForURLAsync(desiredUrl);
}
catch (TimeoutException)
{
Expand Down

0 comments on commit a42aa21

Please sign in to comment.