The following problem only occurs when the web page is used by playwright (C#):
The web page contains a radio button that lets the user change the marital status of himself. When the radio button is used, the viewmodel is updated via session data (Session.Set). There is also a "Save" button to ultimately save the data in the database.
When using playwright, the radio button correctly sets the viewmodel to have the correct marital status, but as soon as the save button is clicked (post request), the updated data is set back to the old data.
Here is the backend code that saves the viewmodel in the session:
public async Task<JsonResult> OnPostUpdateMaritalStatus(string maritalStatus) { try { var vm = GetSessionData(); vm.MaritalStatus = maritalStatus; SaveSessionData(vm); vm = GetSessionData(); // This is to test if SaveSessionData does anything. It seems to save it here correctly, but the data is lost in OnPostSaveBeneficiariesAsync()/ await HttpContext.Session.CommitAsync(); // Hasn't yielded any results. return new JsonResult("Pass"); } catch (Exception) { return new JsonResult("Fail"); throw; } }
Here is "SaveSessionData":
private void SaveSessionData(BeneficiaryViewModel viewModel) { HttpContext.Session.Set(SessionString, viewModel); }
Here is "OnPostSaveAsync" which is called after pressing the save button:
public async Task<IActionResult> OnPostSaveBeneficiariesAsync() { string aeId = HttpContext.Session.GetString(ParticipantSessionStrings.AccountEnrollmentId); var viewModel = GetSessionData(); if (!string.IsNullOrWhiteSpace(viewModel.MaritalStatus)) { if (viewModel.TableData.Where(x => x.Type == "P").Sum(x => x.Beneproceeds).Equals(100) && !viewModel.TableData.Any(x => x.Type == "S")) { if (viewModel.MaritalStatus.Equals("Y", StringComparison.OrdinalIgnoreCase) && viewModel.TableData.FirstOrDefault(x => x.BeneRelationship == Relationships.Spouse)?.Beneproceeds != 100m) { BeneficiaryCurrentStep = BeneficiaryWizardSteps.SpousalConsent; SetTransactionInfo(viewModel); return RedirectToPage(); } BeneficiaryCurrentStep = BeneficiaryWizardSteps.Summary; SetTransactionInfo(viewModel); } else if (viewModel.TableData.Where(x => x.Type == "P").Sum(x => x.Beneproceeds).Equals(100) && viewModel.TableData.Where(x => x.Type == "S").Sum(x => x.Beneproceeds).Equals(100)) { if (viewModel.MaritalStatus.Equals("Y", StringComparison.OrdinalIgnoreCase) && viewModel.TableData.FirstOrDefault(x => x.BeneRelationship == Relationships.Spouse)?.Beneproceeds != 100m) { BeneficiaryCurrentStep = BeneficiaryWizardSteps.SpousalConsent; SetTransactionInfo(viewModel); return RedirectToPage(); } BeneficiaryCurrentStep = BeneficiaryWizardSteps.Summary; SetTransactionInfo(viewModel); } else { BeneficiaryCurrentStep = BeneficiaryWizardSteps.DataEntry; if (viewModel.TableData.Any(x => x.Type == "P") && viewModel.TableData.Any(x => x.Type == "S")) { TempData["UserMessage"] = JsonConvert.SerializeObject(new AlertViewModel() { Title = _localizer["Beneficiary_Error"], Message = String.Format(_localizer["Beneficiary_Primary_Secondary"], viewModel.TableData.Where(x => x.Type == "P").Sum(x => x.Beneproceeds), viewModel.TableData.Where(x => x.Type == "S").Sum(x => x.Beneproceeds)) }); } else if (viewModel.TableData.Any(x => x.Type == "P")) { TempData["UserMessage"] = JsonConvert.SerializeObject(new AlertViewModel() { Title = _localizer["Beneficiary_Error"], Message = String.Format(_localizer["Beneficiary_Total"], viewModel.TableData.Sum(x => x.Beneproceeds)) }); } else if (viewModel.TableData.Any(x => x.Type == "S") && !viewModel.TableData.Any(x => x.Type == "P")) { TempData["UserMessage"] = JsonConvert.SerializeObject(new AlertViewModel() { Title = _localizer["Beneficiary_Error"], Message = _localizer["Beneficiary_None"] }); } else { BeneficiaryCurrentStep = BeneficiaryWizardSteps.Summary; SetTransactionInfo(viewModel); } } } else if (!_planService.PlanRequiresSpouseAsBeneficiary(_accountsProvidedId)) { if (viewModel.TableData.Where(x => x.Type == "P").Sum(x => x.Beneproceeds).Equals(100) && !viewModel.TableData.Any(x => x.Type == "S")) { BeneficiaryCurrentStep = BeneficiaryWizardSteps.Summary; SetTransactionInfo(viewModel); } else if (viewModel.TableData.Where(x => x.Type == "P").Sum(x => x.Beneproceeds).Equals(100) && viewModel.TableData.Where(x => x.Type == "S").Sum(x => x.Beneproceeds).Equals(100)) { BeneficiaryCurrentStep = BeneficiaryWizardSteps.Summary; SetTransactionInfo(viewModel); } else { BeneficiaryCurrentStep = BeneficiaryWizardSteps.DataEntry; if (viewModel.TableData.Any(x => x.Type == "P") && viewModel.TableData.Any(x => x.Type == "S")) { TempData["UserMessage"] = JsonConvert.SerializeObject(new AlertViewModel() { Title = _localizer["Beneficiary_Error"], Message = String.Format(_localizer["Beneficiary_Primary_Secondary"], viewModel.TableData.Where(x => x.Type == "P").Sum(x => x.Beneproceeds), viewModel.TableData.Where(x => x.Type == "S").Sum(x => x.Beneproceeds)) }); } else if (viewModel.TableData.Any(x => x.Type == "P")) { TempData["UserMessage"] = JsonConvert.SerializeObject(new AlertViewModel() { Title = _localizer["Beneficiary_Error"], Message = String.Format(_localizer["Beneficiary_Total"], viewModel.TableData.Sum(x => x.Beneproceeds)) }); } else if (viewModel.TableData.Any(x => x.Type == "S") && !viewModel.TableData.Any(x => x.Type == "P")) { TempData["UserMessage"] = JsonConvert.SerializeObject(new AlertViewModel() { Title = _localizer["Beneficiary_Error"], Message = _localizer["Beneficiary_None"] }); } else { BeneficiaryCurrentStep = BeneficiaryWizardSteps.Summary; SetTransactionInfo(viewModel); } } } else { TempData["UserMessage"] = JsonConvert.SerializeObject(new AlertViewModel() { Title = _localizer["Beneficiary_Error"], Message = _localizer["Beneficiary_Marital"] }); } await HttpContext.Session.CommitAsync(); return RedirectToPage(); }
In "OnPostSaveAsync()", the "GetSessionData()" function retrieves the viewmodel.
Here is "GetSessionData()":
private BeneficiaryViewModel GetSessionData() { return HttpContext.Session.Get<BeneficiaryViewModel>(SessionString); }
Here is the playwright code, which selects the radio button with checkmarks[0].ClickAsync() and clicks the save button with await page.Locator("input[id='save-changes-btn'].First.ClickAsync()
Interestingly enough, if I add delays (commented out) in the playwright code, it works. So it seems as if it is a timing issue, but the web app should be resillient enough to serve a very fast user.