Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove jQuery from Webchat #2379

Merged
merged 7 commits into from
Mar 10, 2022
Merged

Conversation

leenagupte
Copy link
Contributor

@leenagupte leenagupte commented Mar 4, 2022

Trello: https://trello.com/c/jymNmjHN

What's changed?

Remove jQuery from webchat/library.js and webchat.js.

This change is very large, so the initialisation of the code has not been changed, neither has Webchat been converted into a GOVUK module. The focus of this change is just to remove the reliance on jQuery in the Webchat scripts which is a large change by itself.

An anomaly was discovered during the testing of this change.

There is only one webchat page that this script runs on:
/government/organisations/hm-passport-office/contact/hm-passport-office-webchat

The availabilityURL always returns a response of:

{
  "status": "success",
  "response": "UNAVAILABLE"
}

with an http status of 200. This seems incorrect as the openUrl states that all advisors are busy, so we would expect the availabilityURL to return a status of "BUSY".

There is an open ticket to change the URLs, so hopefully that will fix the problem. The removal of jQuery in this change has not negatively affected the workings of Webchat. The behaviour hasn't been affected, even if that behaviour is incorrect.

The response stubbed from the availabilityURL has also been changed in the tests as the switch from using Ajax to calling XMLHttpRequest requires more information from request object (http status code and readyState) to determine when the request has been completed.

Results from testing

Screenshot 2022-03-04 at 14 33 48

Screenshot 2022-03-04 at 14 34 42

⚠️ This repo is Continuously Deployed: make sure you follow the guidance ⚠️

@govuk-ci govuk-ci temporarily deployed to government-f-remove-jqu-lussih March 4, 2022 16:52 Inactive
@leenagupte leenagupte requested a review from andysellick March 4, 2022 16:52
@leenagupte leenagupte force-pushed the remove-jquery-from-webchat-files branch from 948c504 to bf963d6 Compare March 4, 2022 16:54
@govuk-ci govuk-ci temporarily deployed to government-f-remove-jqu-lussih March 4, 2022 16:54 Inactive
@leenagupte leenagupte mentioned this pull request Mar 4, 2022
@andysellick
Copy link
Contributor

Mentioning this for the record. The URL for HMPO is being updated in this PR: #2358

Copy link
Contributor

@andysellick andysellick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Well done for jumping into this tangle. Just a few questions and suggestions.

var $ = window.$

$(document).ready(function () {
document.addEventListener('DOMContentLoaded', function () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recently had to do this exact change in another script and Kevin pointed out it would work just fine by removing the document.ready entirely without replacing it. Can you test whether this would work?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might also be able to to do the following:

(function () {
.... your code
})()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a self executing function in this context would be the same as having the code execute at this point without a document.ready.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooh! Kevin's right. The event listener isn't needed. I'll remove it and fix up.

@@ -27,14 +23,19 @@
if (!availabilityUrl || !openUrl) {
throw Error.new('urls for webchat not defined')
}
$openButton.on('click', handleOpenChat)

if (redirectUrl === true) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious why this if statement wraps the button add listener? I don't see the equivalent in the original code.

Copy link
Contributor Author

@leenagupte leenagupte Mar 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I think I was being overly cautious, because the "open button" only exists when data-redirect is true. However, you are right it in that it's not needed. I'll swap it for your recommendation below. Thanks!

app/assets/javascripts/webchat/library.js Show resolved Hide resolved
@@ -27,14 +23,19 @@
if (!availabilityUrl || !openUrl) {
throw Error.new('urls for webchat not defined')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not your code, but I wonder if we should take this opportunity to improve this error handling. Kevin suggested something like this on a bit of work I did recently:

throw Error.new('urls for webchat not defined', window.location)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would passing window.location.href be more useful than using window.location? The window.location object seems to have a lot of stuff in it:

Screenshot 2022-03-08 at 12 00 59

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either's good.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add this change to a new commit.

app/assets/javascripts/webchat/library.js Show resolved Hide resolved
var currentState = $el.find('.' + webchatStateClass + state)
$el.find('[class^="' + webchatStateClass + '"]').addClass('govuk-!-display-none')
currentState.removeClass('govuk-!-display-none')
var currentState = el.querySelectorAll('[class^="' + webchatStateClass + state + '"]')[0]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In jQuery, .find() finds everything that matches. In JavaScript, it's weirdly more complex

  • querySelector finds the first element that matches
  • querySelectorAll finds all elements that match

If you do querySelectorAll()[0] that returns the first one found - it's equivalent to doing querySelector. Which one do you want to do here? I suspect it's querySelector?

Copy link
Contributor Author

@leenagupte leenagupte Mar 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤦‍♀️ Yes, I just need querySelector.

@leenagupte leenagupte force-pushed the remove-jquery-from-webchat-files branch from bf963d6 to 0208bbe Compare March 8, 2022 13:16
@govuk-ci govuk-ci temporarily deployed to government-f-remove-jqu-lussih March 8, 2022 13:17 Inactive
@leenagupte
Copy link
Contributor Author

@andysellick Thanks for your review. I've made the recommended changes and fixed up.

Copy link
Contributor

@andysellick andysellick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, just one small question.

app/assets/javascripts/webchat.js Show resolved Hide resolved
@leenagupte
Copy link
Contributor Author

When #2358 is merged tomorrow, Webchat will start working again. At that point I will rebase and make sure that this change hasn't broken anything.

@leenagupte leenagupte changed the title Remove jQuery from Webchat [DO NOT MERGE] Remove jQuery from Webchat Mar 9, 2022
This will be required to fake responses from XMLHttpRequest once jQuery
has been removed from webchat.js and webchat/library.js as we will
no longer be able to spyOn ajax and create a fake response.
The linter threw an error as the creation of a new GOVUK.Webchat
object is not being stored in a variable. Storing a variable isn't
appropriate in this case as it would not be used, so the linter is
being ignored.

See: https://stackoverflow.com/questions/33287045/eslint-suppress-do-not-use-new-for-side-effects
The "ready" function in jQuery waits for the DOM tree to load, i.e. be
"ready" before moving on. The equivalent to this in vanilla JS is to
listen for the "DOMContentLoaded" event. However, this script works
without an event listener on "DOMContentLoaded", so the ready function
has just been removed.
@leenagupte leenagupte force-pushed the remove-jquery-from-webchat-files branch from 0208bbe to 787c8bf Compare March 10, 2022 11:10
@govuk-ci govuk-ci temporarily deployed to government-f-remove-jqu-lussih March 10, 2022 11:10 Inactive
@leenagupte
Copy link
Contributor Author

It's currently showing "Advisors are busy" which matches live. I would like to see the pop-up open when advisors are available before merging.

Screenshot 2022-03-10 at 10 23 47

@leenagupte
Copy link
Contributor Author

leenagupte commented Mar 10, 2022

Oh dear. It's seems that the "Advisors are available" message shows. But the link doesn't link to anywhere 😱
Screenshot 2022-03-10 at 11 51 04

@leenagupte
Copy link
Contributor Author

Success! I was defining openButton incorrectly. Rather than:

var openButton = document.getElementsByClassName('.js-webchat-open-button')[0]

it should have been:

var openButton = document.querySelector('.js-webchat-open-button')

Screenshot 2022-03-10 at 13 40 00

I'll update and fix up.

@leenagupte leenagupte force-pushed the remove-jquery-from-webchat-files branch from 787c8bf to c4e5ba6 Compare March 10, 2022 13:44
@govuk-ci govuk-ci temporarily deployed to government-f-remove-jqu-lussih March 10, 2022 13:45 Inactive
@leenagupte leenagupte changed the title [DO NOT MERGE] Remove jQuery from Webchat Remove jQuery from Webchat Mar 10, 2022
This commit replaces like for like jQuery methods with vanilla JS.
Ajax will be removed in a separate commit.
Creates an XMLHttpRequest object to make the request to the availability
url. We need to use XMLHttpRequest rather than the new "await" and
"fetch" functions as they are not supported in Internet Explorer.

There is only one webchat page that this script runs on:
/government/organisations/hm-passport-office/contact/hm-passport-office-webchat

The [availabilityURL] always returns a response of:

```
{
  "status": "success",
  "response": "UNAVAILABLE"
}
```

with an http status of 200. This seems incorrect as the [openUrl] states
that all advisors are busy, so we would expect the availabilityURL to
return a status of "BUSY". There is an [open ticket] to change the URLs,
so hopefully that will fix the problem. The removal of jQuery in this
change has not negatively affected the workings of Webchat. The
behaviour hasn't been affected, even if that behaviour is incorrect.

The XMLHttpRequest is still being called asynchronously like the old
ajax call ("true" in the call to request.open).

`readyState` and the `status` returned by the XMLHttpRequest object
are used to determine whether the request has been successful. That
means how the response is being stubbed in the tests has been changed to
match.

The "mount" function is doing the equivalent of the webchat.js script,
so it has been updated to match that script.

The jsonNormalisedError object had to be updated in the tests, as a
string without a status  was not an accepted response for
XMLHttpRequest.

As ajax has been removed, it can no longer be spied on in the tests.
However, the tests still use jQuery, so jasmine Ajax (installed in a
prior commit) can be used define fake responses from XMLHttpRequest.

XMLHttpRequest makes two calls, to open and send, it was easier to stub
the response of the most recent call rather than trying to mock both.
This means that in test "should only track once per state change" that
tests the URL polling, we only need to change the "most recent" ajax
stub when the response being returned changes. It was much simpler to
just call the "most recent" stub twice than try to replicate the
operation of the fake function.

[availabilityURL]: https://hmpowebchat.klick2contact.com/v03/providers/HMPO/api/availability.php
[openUrl]: https://hmpowebchat.klick2contact.com/v03/launcherV3.php?p=HMPO&d=717&ch=CH&psk=chat_a1&iid=STC&srbp=0&fcl=0&r=Chat&s=https://hmpowebchat.klick2contact.com/v03&u=&wo=&uh=&pid=2&iif=0
[open ticket]: #2358
This will allow us to pinpoint which GOV.UK pages are trying to open a
webchat url, without having any urls defined in [webchat.yaml]

[webchat.yaml]: https://github.com/alphagov/government-frontend/blob/5974c4ec2c7e7a4eedcfda8f48370cce79c8efa0/lib/webchat.yaml
@leenagupte leenagupte force-pushed the remove-jquery-from-webchat-files branch from c4e5ba6 to 5a5e77d Compare March 10, 2022 16:30
@govuk-ci govuk-ci temporarily deployed to government-f-remove-jqu-lussih March 10, 2022 16:30 Inactive
@leenagupte leenagupte merged commit 48127fc into main Mar 10, 2022
@leenagupte leenagupte deleted the remove-jquery-from-webchat-files branch March 10, 2022 16:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants