Author SHA1 Message Date
Robert Bond fdeff5b898 Merged PR 2605: updated query to include consultationclosed check
updated query to include consultationclosed check

Related work items: #24836
2026-09-07 10:46:32 +00:00
Robert Bond 4e9d585566 Merged PR 2596: fix build error
fix build error

Related work items: #24648
2026-09-02 12:37:32 +00:00
Robert Bond b95a20a980 Merged PR 2595: updated regex to exclude bulk annon mailers
updated regex to exclude bulk annon mailers

Related work items: #24648
2026-09-02 08:02:38 +00:00
Robert Bond c9e7743782 Merged PR 2586: update text for reps showing
update text for reps showing

Related work items: #24650
2026-08-25 15:20:56 +00:00
Robert Bond 6bf5918387 Merged PR 2585: added text before make reps button
added text before make reps button

Related work items: #24650
2026-08-25 09:01:11 +00:00
Robert Bond c2d79cf83f Merged PR 2580: fixed the links
fixed the links

Related work items: #24648
2026-08-20 12:54:44 +00:00
Robert Bond 6ba1e16f9a Merged PR 2573: added link to footer
added link to footer

Related work items: #24649
2026-08-18 15:17:25 +00:00
Robert Bond 6cce7d05f1 Merged PR 2572: overlay link to guidance
overlay link to guidance

Related work items: #24650
2026-08-18 15:02:36 +00:00
Robert Bond ac4834a2a4 Merged PR 2570: updated copyright links
updated copyright links

Related work items: #24648
2026-08-18 14:21:54 +00:00
Robert Bond 850006d917 Merged PR 2559: added package lock
added package lock

Related work items: #24389
2026-08-12 14:03:23 +00:00
Robert Bond 478fa91004 Merged PR 2558: updated link on awaiting submission view allin welsh
updated link on awaiting submission view allin welsh

Related work items: #24389
2026-08-12 13:58:07 +00:00
Robert Bond 5813d409bc Merged PR 2557: removed field
removed field

Related work items: #24554
2026-08-11 09:26:07 +00:00
Robert Bond 71035a054f Merged PR 2556: updated welsh translation
updated welsh translation

Related work items: #24389
2026-08-11 09:13:22 +00:00
Robert Bond c2c4690b9b Merged PR 2555: missing slash in welsh url for case link
missing slash in welsh url for case link

Related work items: #24389
2026-08-10 13:11:18 +00:00
Robert Bond 9e2461305f Merged PR 2546: upodated copy
upodated copy

Related work items: #24335
2026-08-05 11:40:56 +00:00
Robert Bond db07425788 Merged PR 2541: update description for case closed
update description for case closed

Related work items: #24335
2026-08-05 08:31:17 +00:00
Robert Bond 90e8cacf67 Merged PR 2537: adjusted back button on first page of reopend rep
adjusted back button on first page of reopend rep

Related work items: #24488
2026-08-04 10:42:07 +00:00
Robert Bond 6462bd5163 Merged PR 2536: updated path to wrapper to fix build error
updated path to wrapper to fix build error

Related work items: #24215
2026-08-04 08:30:13 +00:00
Robert Bond d190fa8ff7 Merged PR 2534: adjusted breadcrumb for viewall return from a case
adjusted breadcrumb for viewall return from a case

Related work items: #24389
2026-08-04 08:09:04 +00:00
36 changed files with 2044 additions and 56 deletions
+11 -1
View File
@@ -72,7 +72,17 @@ export default function AIPolicyNotice() {
{t("home:ai-policy-notice-paragraph-one")} {t("home:ai-policy-notice-paragraph-one")}
</p> </p>
<p className="govuk-body govuk-!-margin-bottom-4"> <p className="govuk-body govuk-!-margin-bottom-4">
{t("home:ai-policy-notice-paragraph-two")} {t("home:ai-policy-notice-paragraph-two")}{" "}
<a
target="_blank"
rel="noopener noreferrer"
href={t(
"home:ai-policy-notice-paragraph-two-a-link"
)}
>
{t("home:ai-policy-notice-paragraph-two-a-label")}
</a>{" "}
{t("home:ai-policy-notice-paragraph-two-b")}
</p> </p>
<button <button
ref={dismissButtonRef} ref={dismissButtonRef}
+1 -1
View File
@@ -91,7 +91,7 @@ const Breadcrumbs = (props) => {
watchedCases: () => t("myportal:watchedcases-card-title"), watchedCases: () => t("myportal:watchedcases-card-title"),
myCases: () => t("myportal:mycases-card-title"), myCases: () => t("myportal:mycases-card-title"),
myRepresentations: () => t("myportal:myrepresentations-card-title"), myRepresentations: () => t("myportal:myrepresentations-card-title"),
mySubmittedReps: "Submitted representations" mySubmittedReps: () => t("myportal:submitted-reps-card-title")
}; };
const viewAllLabelResolver = labelsByKey[viewKey]; const viewAllLabelResolver = labelsByKey[viewKey];
+4 -2
View File
@@ -1006,8 +1006,10 @@ let MakeRepresentation = (props) => {
appealIsConsultation={appealIsConsultation} appealIsConsultation={appealIsConsultation}
currentReference={ticketnumber} currentReference={ticketnumber}
caseTitle={ caseTitle={
currentView.currentReference || currentView?.caseReference?.repDetails
currentView.caseReference.currentReference ?.pinswg_name ||
currentView?.currentReference ||
currentView?.caseReference.currentReference
} }
whichControl={whichControl} whichControl={whichControl}
appealIsLocalImpact={appealIsLocalImpact} appealIsLocalImpact={appealIsLocalImpact}
+47
View File
@@ -877,6 +877,52 @@ const CaseSummary = (props) => {
<div className="govuk-grid-row"> <div className="govuk-grid-row">
<div className="govuk-grid-column-full"> <div className="govuk-grid-column-full">
<div className=""> <div className="">
{getFormCollectionByID(
appealTypeID
).PrimaryIdAttribute ==
"pinswg_sipscase" &&
isConsultationWindowOpen(
detailsObj
) && (
<p>
{t(
"case:summary-make-consultation-response-para-a"
)}
<Link
target="_blank"
className="govuk-link"
href={t(
"case:summary-make-representation-para-a-link"
)}
>
{t(
"case:summary-make-representation-para-a-label"
)}
</Link>
</p>
)}
{isGeneralRepresentationWindowOpen(
detailsObj
) && (
<div className="govuk-button-group">
<p>
{t(
"case:summary-make-representation-para-a"
)}
<Link
target="_blank"
className="govuk-link"
href={t(
"case:summary-make-representation-para-a-link"
)}
>
{t(
"case:summary-make-representation-para-a-label"
)}
</Link>
</p>
</div>
)}
<div className="govuk-button-group"> <div className="govuk-button-group">
{getFormCollectionByID( {getFormCollectionByID(
appealTypeID appealTypeID
@@ -983,6 +1029,7 @@ const CaseSummary = (props) => {
)} )}
</> </>
)} )}
{isGeneralRepresentationWindowOpen( {isGeneralRepresentationWindowOpen(
detailsObj detailsObj
) && ( ) && (
@@ -570,7 +570,7 @@ const Pinswg_sipscase = (props) => {
)} )}
</h4> </h4>
<dl className="govuk-summary-list govuk-!-font-size-16 govuk-!-margin-bottom-9"> <dl className="govuk-summary-list govuk-!-font-size-16 govuk-!-margin-bottom-9">
<SummaryRow {/* <SummaryRow
label={t( label={t(
"case:summary-valid-notice-of-intention-to-submit-an-application" "case:summary-valid-notice-of-intention-to-submit-an-application"
)} )}
@@ -592,7 +592,7 @@ const Pinswg_sipscase = (props) => {
"case:summary-awaiting-information-label" "case:summary-awaiting-information-label"
) )
} }
/> /> */}
<SummaryRow <SummaryRow
label={t( label={t(
"case:summary-written-acceptance-of-notice" "case:summary-written-acceptance-of-notice"
+27 -14
View File
@@ -108,7 +108,7 @@ export default function Footer(props) {
> >
<span className="vo_hidden"> <span className="vo_hidden">
{t( {t(
"common:social-bar-share-via-link", "common:social-bar-share-via-link"
)}{" "} )}{" "}
</span> </span>
Twitter Twitter
@@ -186,37 +186,37 @@ export default function Footer(props) {
<li className="govuk-footer__inline-list-item govuk-!-font-weight-bold govuk-!-margin-right-7"> <li className="govuk-footer__inline-list-item govuk-!-font-weight-bold govuk-!-margin-right-7">
<a <a
href={t( href={t(
"common:footer-guidance-link", "common:footer-guidance-link"
)} )}
className="nav-link" className="nav-link"
> >
{t( {t(
"common:footer-guidance-link-label", "common:footer-guidance-link-label"
)} )}
</a> </a>
</li> </li>
<li className="govuk-footer__inline-list-item govuk-!-font-weight-bold govuk-!-margin-right-7"> <li className="govuk-footer__inline-list-item govuk-!-font-weight-bold govuk-!-margin-right-7">
<a <a
href={t( href={t(
"common:footer-announcements-link", "common:footer-announcements-link"
)} )}
className="nav-link" className="nav-link"
> >
{t( {t(
"common:footer-announcements-link-label", "common:footer-announcements-link-label"
)} )}
</a> </a>
</li> </li>
<li className="govuk-footer__inline-list-item govuk-!-font-weight-bold"> <li className="govuk-footer__inline-list-item govuk-!-font-weight-bold">
<a <a
href={t( href={t(
"common:footer-contact-us-link", "common:footer-contact-us-link"
)} )}
className="govuk-footer__link" className="govuk-footer__link"
id="aContactUs" id="aContactUs"
> >
{t( {t(
"common:footer-contact-us-link-label", "common:footer-contact-us-link-label"
)} )}
</a> </a>
</li> </li>
@@ -236,7 +236,7 @@ export default function Footer(props) {
id="aAccessibility" id="aAccessibility"
> >
{t( {t(
"common:footer-accessibility-link-label", "common:footer-accessibility-link-label"
)} )}
</Link> </Link>
</li> </li>
@@ -257,13 +257,13 @@ export default function Footer(props) {
<li className="govuk-footer__inline-list-item"> <li className="govuk-footer__inline-list-item">
<a <a
href={t( href={t(
"common:footer-copyright-link", "common:footer-copyright-link"
)} )}
className="govuk-footer__link" className="govuk-footer__link"
id="Access" id="Access"
> >
{t( {t(
"common:footer-copyright-link-label", "common:footer-copyright-link-label"
)} )}
</a> </a>
</li> </li>
@@ -271,13 +271,13 @@ export default function Footer(props) {
<li className="govuk-footer__inline-list-item"> <li className="govuk-footer__inline-list-item">
<Link <Link
href={t( href={t(
"common:footer-privacy-link", "common:footer-privacy-link"
)} )}
id="aPrivacy" id="aPrivacy"
className="govuk-footer__link" className="govuk-footer__link"
> >
{t( {t(
"common:footer-privacy-link-label", "common:footer-privacy-link-label"
)} )}
</Link> </Link>
</li> </li>
@@ -285,13 +285,26 @@ export default function Footer(props) {
<li className="govuk-footer__inline-list-item"> <li className="govuk-footer__inline-list-item">
<Link <Link
href={t( href={t(
"common:footer-terms-conditions-link", "common:footer-terms-conditions-link"
)} )}
id="aTermsConds" id="aTermsConds"
className="govuk-footer__link" className="govuk-footer__link"
> >
{t( {t(
"common:footer-terms-conditions-link-label", "common:footer-terms-conditions-link-label"
)}
</Link>
</li>
<li className="govuk-footer__inline-list-item">
<Link
href={t(
"common:footer-pedw-use-ai-link"
)}
id="aHowToAI"
className="govuk-footer__link"
>
{t(
"common:footer-pedw-use-ai-label"
)} )}
</Link> </Link>
</li> </li>
+2 -6
View File
@@ -212,12 +212,8 @@ const ViewAllResults = (props) => {
} }
if (isAwaitingSubmissionDetails) { if (isAwaitingSubmissionDetails) {
if (router.locale === "cy") {
return "/fymhorth/parhauigyflwyno";
}
return ( return (
"/myportal" + (router.locale === "cy" ? "/fymhorth" : "/myportal") +
"/" + "/" +
getFormCollectionByID(item.pinswg_appealcasetype).UrlName + getFormCollectionByID(item.pinswg_appealcasetype).UrlName +
"?lpa=" + "?lpa=" +
@@ -235,7 +231,7 @@ const ViewAllResults = (props) => {
if (router.locale === "cy") { if (router.locale === "cy") {
return myportal === true return myportal === true
? "/fymhorth/achos" + ? "/fymhorth/achos/" +
item.ticketnumber + item.ticketnumber +
"?key=" + "?key=" +
currentViewKey + currentViewKey +
+3 -3
View File
@@ -88,9 +88,9 @@ module.exports = {
"/details-about-cookies": ["common", "cookies"], "/details-about-cookies": ["common", "cookies"],
"/terms-and-conditions": ["common"], "/terms-and-conditions": ["common"],
"/account/passwordreset": ["common", "home"], "/account/passwordreset": ["common", "home"],
"/auth/signin": ["common", "common", "auth"], "/auth/signin": ["common", "account", "auth"],
"/auth/verify-request": ["common", "common", "auth"], "/auth/verify-request": ["common", "account", "auth"],
"/auth/error": ["common", "common", "auth"], "/auth/error": ["common", "account", "auth"],
"/admin": ["case"] "/admin": ["case"]
} }
}; };
+10 -4
View File
@@ -219,10 +219,10 @@ export const createRepresentationRouteRenderers = ({
currentView.representationSubmitConfirmation !== true && currentView.representationSubmitConfirmation !== true &&
renderBackCrumb(onRepresentationSubmitBackFromConfirmation)} renderBackCrumb(onRepresentationSubmitBackFromConfirmation)}
{currentView.representationSubmit !== true && {/* {currentView.representationSubmit !== true &&
hasRepDetails && hasRepDetails &&
repDetails?.representationType !== "Questionnaire" && repDetails?.representationType !== "Questionnaire" &&
renderBackCrumb(onRepresentationSubmitBackToDetails)} renderBackCrumb(onRepresentationSubmitBackToDetails)} */}
{currentView.representationSubmit !== true && {currentView.representationSubmit !== true &&
hasRepDetails && hasRepDetails &&
@@ -318,7 +318,10 @@ export const createCaseDetailRouteRenderers = ({
if (va === "true") { if (va === "true") {
return ( return (
<> <>
{renderLinkCrumb("/myportal/viewall", getViewAllLabel(key))} {renderLinkCrumb(
`/myportal/viewall?key=${key}`,
getViewAllLabel(key)
)}
{renderCaseReferenceCrumb(fallbackSearchTitle)} {renderCaseReferenceCrumb(fallbackSearchTitle)}
</> </>
); );
@@ -377,7 +380,10 @@ export const createCaseDetailRouteRenderers = ({
return ( return (
<> <>
{renderMyPortalCrumb()} {renderMyPortalCrumb()}
{renderLinkCrumb("/myportal/viewall", getViewAllLabel(key))} {renderLinkCrumb(
`/myportal/viewall?key=${key}`,
getViewAllLabel(key)
)}
{renderCaseReferenceCrumb(caseReferenceDisplay)} {renderCaseReferenceCrumb(caseReferenceDisplay)}
</> </>
); );
+1 -1
View File
@@ -28,7 +28,7 @@
"case-closed-desc": "Mae PCAC wedi penderfynu ar yr apêl ac mae'r achos bellach wedi'i gau.", "case-closed-desc": "Mae PCAC wedi penderfynu ar yr apêl ac mae'r achos bellach wedi'i gau.",
"case-closed-desc-order": "Mae PCAC wedi penderfynu ar y gorchymyn ac mae'r achos bellach wedi'i gau.", "case-closed-desc-order": "Mae PCAC wedi penderfynu ar y gorchymyn ac mae'r achos bellach wedi'i gau.",
"case-closed-desc-application": "Mae PCAC wedi penderfynu ar yr apêl ac mae'r achos bellach wedi'i gau.", "case-closed-desc-application": "Mae PCAC wedi penderfynu ar yr apêl ac mae'r achos bellach wedi'i gau.",
"case-closed-desc-dnssips": "Mae'r Cais wedi'i benderfynu.", "case-closed-desc-dnssips": "Mae'r achos bellach wedi'i gau. Ni chymerir camau pellach yn yr achos hwn",
"case-closed-desc-callin": "Mae PCAC wedi penderfynu ar y cais a alwyd i mewn ac mae'r achos bellach wedi'i gau.", "case-closed-desc-callin": "Mae PCAC wedi penderfynu ar y cais a alwyd i mewn ac mae'r achos bellach wedi'i gau.",
"appeal-submitted": "Apêl wedi'i Chyflwyno", "appeal-submitted": "Apêl wedi'i Chyflwyno",
"appeal-submitted-desc": "Mae PCAC wedi derbyn yr apêl.", "appeal-submitted-desc": "Mae PCAC wedi derbyn yr apêl.",
+5 -1
View File
@@ -17,6 +17,10 @@
"summary-case-stage-label": "Cam yr Achos", "summary-case-stage-label": "Cam yr Achos",
"summary-environmental-statement-label": "Lleoliad Datganiad Amgylcheddol", "summary-environmental-statement-label": "Lleoliad Datganiad Amgylcheddol",
"summary-last-modified-label": "Addaswyd ddiwethaf", "summary-last-modified-label": "Addaswyd ddiwethaf",
"summary-make-consultation-response-para-a": "Gellir cyflwyno ymatebion i ymgynghoriadau, neu sylwadau, ar gyfer yr achos hwn bellach. I gael rhagor o wybodaeth am gyflwyno sylwadau i PCAC, gweler ein ",
"summary-make-representation-para-a": "Gellir cyflwyno sylwadau, neu gynrychioliadau, ar gyfer yr achos hwn bellach. I gael rhagor o wybodaeth am gyflwyno sylwadau i PCAC, gweler ein ",
"summary-make-representation-para-a-link": "https://www.llyw.cymru/defnyddio-deallusrwydd-artiffisial-ai-mewn-cyflwyniadau-i-pcac",
"summary-make-representation-para-a-label": "Canllawiau ar ddefnyddio Deallusrwydd Artiffisial Cynhyrchiol",
"summary-make-representation-label": "Cyflwyno sylwadau", "summary-make-representation-label": "Cyflwyno sylwadau",
"summary-make-consultation-label": "Cyflwyno Ymateb i'r Ymgynghoriad", "summary-make-consultation-label": "Cyflwyno Ymateb i'r Ymgynghoriad",
"summary-representation-open-label": "Cynrychioliadau yn agor", "summary-representation-open-label": "Cynrychioliadau yn agor",
@@ -179,4 +183,4 @@
"summary-comp-acquisition-variation-accepted": "Newid i Gaffael Gorfodol wedi'i Dderbyn", "summary-comp-acquisition-variation-accepted": "Newid i Gaffael Gorfodol wedi'i Dderbyn",
"summary-scheme-ammendment-request-submitted": "Cais i Newid Cynllun/Gorchymyn wedi'i Gyflwyno", "summary-scheme-ammendment-request-submitted": "Cais i Newid Cynllun/Gorchymyn wedi'i Gyflwyno",
"summary-scheme-ammendment-request-accepted": "Cais i Newid Cynllun/Gorchymyn wedi'i Dderbyn" "summary-scheme-ammendment-request-accepted": "Cais i Newid Cynllun/Gorchymyn wedi'i Dderbyn"
} }
+3 -1
View File
@@ -20,6 +20,8 @@
"cancel-link": "Canslo", "cancel-link": "Canslo",
"save-exit-button": "Cadw a gadael", "save-exit-button": "Cadw a gadael",
"submit-and-start": "Cyflwyno a dechrau'r cwrs", "submit-and-start": "Cyflwyno a dechrau'r cwrs",
"footer-pedw-use-ai-label": "Sut mae PCAC yn defnyddio deallusrwydd artiffisial (AI)",
"footer-pedw-use-ai-link": "https://www.llyw.cymru/penderfyniadau-cynllunio-ac-amgylchedd-cymru/sut-mae-pcac-yn-defnyddio-deallusrwydd-artiffisial-ai",
"footer-terms-conditions-link-label": "Telerau ac amodau", "footer-terms-conditions-link-label": "Telerau ac amodau",
"footer-terms-conditions-link": "https://llyw.cymru/gwaith-achos-cynllunio-telerau-ac-amodau", "footer-terms-conditions-link": "https://llyw.cymru/gwaith-achos-cynllunio-telerau-ac-amodau",
"footer-privacy-link-label": "Preifatrwydd", "footer-privacy-link-label": "Preifatrwydd",
@@ -32,7 +34,7 @@
"footer-contact-us-link-label": "Cysylltu â ni", "footer-contact-us-link-label": "Cysylltu â ni",
"footer-contact-us-link": "https://llyw.cymru/penderfyndiadau-cynllunio-ac-amgylchedd-cymru/cysylltwch-ni", "footer-contact-us-link": "https://llyw.cymru/penderfyndiadau-cynllunio-ac-amgylchedd-cymru/cysylltwch-ni",
"footer-copyright-link-label": "Datganiad hawlfraint", "footer-copyright-link-label": "Datganiad hawlfraint",
"footer-copyright-link": "https://llyw.cymru/datganiad-hawlfraint", "footer-copyright-link": "https://www.llyw.cymru/penderfyniadau-cynllunio-ac-amgylchedd-cymru/datganiad-hawlfraint",
"footer-alternative-languages-link-label": "Ieithoedd amgen", "footer-alternative-languages-link-label": "Ieithoedd amgen",
"footer-alternative-languages-link": "https://llyw.cymru/ieithoedd-amgen", "footer-alternative-languages-link": "https://llyw.cymru/ieithoedd-amgen",
"footer-guidance-link-label": "Canllawiau a gwasanaethau Penderfyniadau Cynllunio ac Amgylchedd Cymru", "footer-guidance-link-label": "Canllawiau a gwasanaethau Penderfyniadau Cynllunio ac Amgylchedd Cymru",
+5 -2
View File
@@ -56,9 +56,12 @@
"signin-benefits-paragraph": "Drwy fewngofnodi gyda'r botwm Mewngofnodi, byddwch yn gallu:", "signin-benefits-paragraph": "Drwy fewngofnodi gyda'r botwm Mewngofnodi, byddwch yn gallu:",
"ai-policy-notice-title": "Pwysig: canllawiau ar ddefnyddio cynnwys a gynhyrchir gan AI", "ai-policy-notice-title": "Pwysig: canllawiau ar ddefnyddio cynnwys a gynhyrchir gan AI",
"ai-policy-notice-paragraph-one": "Deellir y gall partïon ddewis defnyddio Deallusrwydd Artiffisial Cynhyrchiol (AI) wrth gyflwyno apeliadau neu gynrychioliadau i PCAC. Er bod gan y rhai sy'n ymgysylltu â PCAC hawl i ddefnyddio AI i gynorthwyo eu cyflwyniadau, dylid nodi y gall cynnwys a gynhyrchir gan AI gynnwys honiadau ffug neu ddi-sail.", "ai-policy-notice-paragraph-one": "Deellir y gall partïon ddewis defnyddio Deallusrwydd Artiffisial Cynhyrchiol (AI) wrth gyflwyno apeliadau neu gynrychioliadau i PCAC. Er bod gan y rhai sy'n ymgysylltu â PCAC hawl i ddefnyddio AI i gynorthwyo eu cyflwyniadau, dylid nodi y gall cynnwys a gynhyrchir gan AI gynnwys honiadau ffug neu ddi-sail.",
"ai-policy-notice-paragraph-two": "Gan y bydd cyflwyniadau ysgrifenedig yn destun craffu yn y broses apelio, o bosibl o dan groesholiad mewn gwrandawiadau ac ymholiadau, ni ddylech wneud cyflwyniadau ysgrifenedig nad ydych yn eu deall neu'n gwybod eu bod yn gywir. Gall cyflwyno tystiolaeth anghywir arwain at gost ddiangen wrth wirio neu wrthbrofi tystiolaeth o'r fath a gallai arwain at ddyfarnu costau yn eich erbyn. Gweler ein Canllawiau ar gyfer defnyddio AI Cynhyrchiol am ragor o wybodaeth.", "ai-policy-notice-paragraph-two": "Gan y bydd cyflwyniadau ysgrifenedig yn destun craffu yn y broses apelio ac o bosibl yn destun croesholi mewn gwrandawiadau ac ymchwiliadau ni ddylech wneud cyflwyniadau ysgrifenedig nad ydych yn eu deall neu nad ydych yn gwybod eu bod yn gywir. Gall cyflwyno tystiolaeth anghywir arwain at gostau diangen wrth wirio neu wrthbrofi'r dystiolaeth honno, a gallai arwain at orchymyn i chi dalu costau. Gweler ein ",
"ai-policy-notice-paragraph-two-a-label": "Canllawiau ar ddefnyddio Deallusrwydd Artiffisial (AI) Cynhyrchiol",
"ai-policy-notice-paragraph-two-a-link": "https://www.llyw.cymru/defnyddio-deallusrwydd-artiffisial-ai-mewn-cyflwyniadau-i-pcac",
"ai-policy-notice-paragraph-two-b": " am ragor o wybodaeth.",
"ai-policy-notice-dismiss-button": "Rwy'n deall", "ai-policy-notice-dismiss-button": "Rwy'n deall",
"contact-us-heading": "Cysylltu â ni", "contact-us-heading": "Cysylltu â ni",
"contact-us-paragraph": "Os oes gennych unrhyw ymholiadau ynghylch apêl, cais neu unrhyw beth arall sy'n ymwneud â Gwaith Achos Cynllunio, gallwch gysylltu â ni", "contact-us-paragraph": "Os oes gennych unrhyw ymholiadau ynghylch apêl, cais neu unrhyw beth arall sy'n ymwneud â Gwaith Achos Cynllunio, gallwch gysylltu â ni",
"contact-us-button": "Cysylltu â ni" "contact-us-button": "Cysylltu â ni"
} }
+1 -1
View File
@@ -28,7 +28,7 @@
"case-closed-desc": "PEDW has determined the appeal and the case has now been closed.", "case-closed-desc": "PEDW has determined the appeal and the case has now been closed.",
"case-closed-desc-order": "PEDW has determined the order and the case has now been closed.", "case-closed-desc-order": "PEDW has determined the order and the case has now been closed.",
"case-closed-desc-application": "PEDW has determined the application and the case has now been closed.", "case-closed-desc-application": "PEDW has determined the application and the case has now been closed.",
"case-closed-desc-dnssips": "The Application has been decided.", "case-closed-desc-dnssips": "The case has now been closed. No further action will be taken on this case",
"case-closed-desc-callin": "PEDW has determined the called-in application and the case has now been closed.", "case-closed-desc-callin": "PEDW has determined the called-in application and the case has now been closed.",
"appeal-submitted": "Appeal Submitted", "appeal-submitted": "Appeal Submitted",
"appeal-submitted-desc": "Appeal has been received by PEDW.", "appeal-submitted-desc": "Appeal has been received by PEDW.",
+5 -1
View File
@@ -17,6 +17,10 @@
"summary-case-stage-label": "Case Stage", "summary-case-stage-label": "Case Stage",
"summary-environmental-statement-label": "Environmental Statement Location", "summary-environmental-statement-label": "Environmental Statement Location",
"summary-last-modified-label": "Last modified", "summary-last-modified-label": "Last modified",
"summary-make-consultation-response-para-a": "Consultations responses, or comments, may now be submitted for this case. For further information on making submissions to PEDW, please see our ",
"summary-make-representation-para-a": "Representations, or comments, may now be submitted for this case. For further information on making submissions to PEDW, please see our ",
"summary-make-representation-para-a-link": "https://www.gov.wales/using-ai-submissions-pedw",
"summary-make-representation-para-a-label": "Guidance for the use of Generative AI",
"summary-make-representation-label": "Make representation", "summary-make-representation-label": "Make representation",
"summary-make-consultation-label": "Submit a Consultation Response", "summary-make-consultation-label": "Submit a Consultation Response",
"summary-representation-open-label": "Representations open", "summary-representation-open-label": "Representations open",
@@ -180,4 +184,4 @@
"summary-comp-acquisition-variation-accepted": "Compulsory Acquisition Variation Accepted", "summary-comp-acquisition-variation-accepted": "Compulsory Acquisition Variation Accepted",
"summary-scheme-ammendment-request-submitted": "Scheme/Order Amendment Request Submitted", "summary-scheme-ammendment-request-submitted": "Scheme/Order Amendment Request Submitted",
"summary-scheme-ammendment-request-accepted": "Scheme/Order Amendment Request Accepted" "summary-scheme-ammendment-request-accepted": "Scheme/Order Amendment Request Accepted"
} }
+4 -2
View File
@@ -20,6 +20,8 @@
"cancel-link": "Cancel", "cancel-link": "Cancel",
"save-exit-button": "Save and exit", "save-exit-button": "Save and exit",
"submit-and-start": "Submit and start course", "submit-and-start": "Submit and start course",
"footer-pedw-use-ai-label": "How PEDW uses AI",
"footer-pedw-use-ai-link": "https://www.gov.wales/planning-and-environment-decisions-wales/how-pedw-uses-ai",
"footer-terms-conditions-link-label": "Terms and conditions", "footer-terms-conditions-link-label": "Terms and conditions",
"footer-terms-conditions-link": "https://gov.wales/planning-casework-terms-and-conditions", "footer-terms-conditions-link": "https://gov.wales/planning-casework-terms-and-conditions",
"footer-privacy-link-label": "Privacy", "footer-privacy-link-label": "Privacy",
@@ -30,9 +32,9 @@
"footer-accessibility-link": "/accessibility", "footer-accessibility-link": "/accessibility",
"footer-feedback-link": "Give feedback about this page", "footer-feedback-link": "Give feedback about this page",
"footer-contact-us-link-label": "Contact us", "footer-contact-us-link-label": "Contact us",
"footer-contact-us-link": "https://gov.wales/planning-and-environment-decisions-wales/contact-us", "footer-contact-us-link": "https://www.gov.wales/planning-and-environment-decisions-wales/contact-us",
"footer-copyright-link-label": "Copyright statement", "footer-copyright-link-label": "Copyright statement",
"footer-copyright-link": "https://gov.wales/copyright-statement", "footer-copyright-link": "https://www.gov.wales/planning-and-environment-decisions-wales/copyright-statement",
"footer-alternative-languages-link-label": "Alternative languages", "footer-alternative-languages-link-label": "Alternative languages",
"footer-alternative-languages-link": "https://gov.wales/alternative-languages", "footer-alternative-languages-link": "https://gov.wales/alternative-languages",
"footer-guidance-link-label": "Planning and Environment Decisions Wales guidance and services", "footer-guidance-link-label": "Planning and Environment Decisions Wales guidance and services",
+4 -1
View File
@@ -56,7 +56,10 @@
"signin-benefits-paragraph": "By signing in with the Sign in button, you will be able to:", "signin-benefits-paragraph": "By signing in with the Sign in button, you will be able to:",
"ai-policy-notice-title": "Important: guidance on use of AI-generated content", "ai-policy-notice-title": "Important: guidance on use of AI-generated content",
"ai-policy-notice-paragraph-one": "It is understood that parties may choose to make use of Generative Artificial Intelligence (AI) when submitting appeals or representations to PEDW. While those engaging with PEDW are entitled to use AI to aid their submissions, it should be noted that content generated by an AI may include false or unsubstantiated claims.", "ai-policy-notice-paragraph-one": "It is understood that parties may choose to make use of Generative Artificial Intelligence (AI) when submitting appeals or representations to PEDW. While those engaging with PEDW are entitled to use AI to aid their submissions, it should be noted that content generated by an AI may include false or unsubstantiated claims.",
"ai-policy-notice-paragraph-two": "As written submissions will be subject to scrutiny in the appeals process, potentially under cross-examination at hearings and inquiries, you should not make written submissions that you do not understand or know to be accurate. The submission of inaccurate evidence may incur unnecessary expense verifying or rebutting such evidence and could lead to an award of costs against you. Please see our Guidance for the use of Generative AI for further information.", "ai-policy-notice-paragraph-two": "As written submissions will be subject to scrutiny in the appeals process, potentially under cross-examination at hearings and inquiries, you should not make written submissions that you do not understand or know to be accurate. The submission of inaccurate evidence may incur unnecessary expense verifying or rebutting such evidence and could lead to an award of costs against you. Please see our ",
"ai-policy-notice-paragraph-two-a-label": "Guidance for the use of Generative AI",
"ai-policy-notice-paragraph-two-a-link": "https://www.gov.wales/using-ai-submissions-pedw",
"ai-policy-notice-paragraph-two-b": " for further information.",
"ai-policy-notice-dismiss-button": "I understand", "ai-policy-notice-dismiss-button": "I understand",
"contact-us-heading": "Contact us", "contact-us-heading": "Contact us",
"contact-us-paragraph": "If you have any queries on an appeal, application or anything else regarding Planning Caserwork you can contact us", "contact-us-paragraph": "If you have any queries on an appeal, application or anything else regarding Planning Caserwork you can contact us",
+66
View File
@@ -87,6 +87,7 @@
"xpath": "^0.0.32" "xpath": "^0.0.32"
}, },
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.62.1",
"eslint": "^8.57.0", "eslint": "^8.57.0",
"eslint-config-next": "^14.2.28", "eslint-config-next": "^14.2.28",
"eslint-plugin-jsdoc": "^48.2.3", "eslint-plugin-jsdoc": "^48.2.3",
@@ -1386,6 +1387,22 @@
"url": "https://opencollective.com/unts" "url": "https://opencollective.com/unts"
} }
}, },
"node_modules/@playwright/test": {
"version": "1.62.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.62.1.tgz",
"integrity": "sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": {
"playwright": "1.62.1"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=20"
}
},
"node_modules/@popperjs/core": { "node_modules/@popperjs/core": {
"version": "2.11.8", "version": "2.11.8",
"license": "MIT", "license": "MIT",
@@ -8323,6 +8340,53 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/playwright": {
"version": "1.62.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.62.1.tgz",
"integrity": "sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.62.1"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=20"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/playwright-core": {
"version": "1.62.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.62.1.tgz",
"integrity": "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==",
"devOptional": true,
"license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
},
"engines": {
"node": ">=20"
}
},
"node_modules/playwright/node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/possible-typed-array-names": { "node_modules/possible-typed-array-names": {
"version": "1.0.0", "version": "1.0.0",
"dev": true, "dev": true,
@@ -9909,6 +9973,8 @@
}, },
"node_modules/string-width/node_modules/emoji-regex": { "node_modules/string-width/node_modules/emoji-regex": {
"version": "8.0.0", "version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"devOptional": true, "devOptional": true,
"license": "MIT" "license": "MIT"
}, },
+6 -2
View File
@@ -12,8 +12,11 @@
"start": "NODE_ENV=production node_modules/next/dist/bin/next start", "start": "NODE_ENV=production node_modules/next/dist/bin/next start",
"lint": "next lint", "lint": "next lint",
"prisma:generate": "prisma generate", "prisma:generate": "prisma generate",
"test:reps": "cd '../../welsh government/Playwright/Playwright' && npx playwright test tests/loggedin/raiserep.spec.js --headed", "test": "playwright test",
"test:newappeal": "cd '../../welsh government/Playwright/Playwright' && npx playwright test tests/loggedin/newappeal.spec.js --headed" "test:reps": "playwright test pwe2e/tests/loggedin/raiserep.spec.js --headed",
"test:newappeal": "playwright test pwe2e/tests/loggedin/newappeal.spec.js --headed",
"test:headed": "playwright test --headed",
"install:browsers": "playwright install chromium"
}, },
"browser": { "browser": {
"child_process": false "child_process": false
@@ -102,6 +105,7 @@
"@react-pdf/pdfkit": "3.1.0" "@react-pdf/pdfkit": "3.1.0"
}, },
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.62.1",
"eslint": "^8.57.0", "eslint": "^8.57.0",
"eslint-config-next": "^14.2.28", "eslint-config-next": "^14.2.28",
"eslint-plugin-jsdoc": "^48.2.3", "eslint-plugin-jsdoc": "^48.2.3",
+17 -3
View File
@@ -372,16 +372,30 @@ export default async function CombinedApiProxy(req, res) {
} }
// === Fetch Reps open events === // === Fetch Reps open events ===
let repsPeriods; let repsPeriods = [];
try { try {
const repsQuery = `pinswg_sipses?$filter=_pinswg_sipscase_value eq ${incidentID} and pinswg_consultationopen ne null &$select=pinswg_consultationopen,pinswg_consultationclose`; const repsQuery =
`pinswg_sipses?` +
`$filter=_pinswg_sipscase_value eq ${incidentID} ` +
`and pinswg_consultationopen ne null ` +
`and (pinswg_consultationclose eq null or pinswg_consultationclose ge ${nowStr})` +
`&$select=pinswg_consultationopen,pinswg_consultationclose`;
const repsRes = await axios.get( const repsRes = await axios.get(
WEBAPI_URL + repsQuery + hashAPIPath(repsQuery), WEBAPI_URL + repsQuery + hashAPIPath(repsQuery),
azureHeaders(token.access_token) azureHeaders(token.access_token)
); );
repsPeriods = repsRes.data.value; const repsRecords = repsRes.data.value;
repsPeriods = repsRecords.filter((period) => {
if (!period.pinswg_consultationclose) {
return true;
}
return new Date(period.pinswg_consultationclose) >= now;
});
} catch (err) { } catch (err) {
consoleLogger( consoleLogger(
`Reps fetch failed for incidentID: ${incidentID}` `Reps fetch failed for incidentID: ${incidentID}`
+33 -5
View File
@@ -14,13 +14,25 @@ const SignIn = (props) => {
const { footerLinks, pages, csrfToken, callbackUrl } = props; const { footerLinks, pages, csrfToken, callbackUrl } = props;
const [buttonDisabled, setButtonDisabled] = useState(false); const [buttonDisabled, setButtonDisabled] = useState(false);
const [emailError, setEmailError] = useState("");
const emailRegex =
/^(?!.*(?:.+\.)?(?:burpcollaborator\.net|interactsh\.com|mailinator\.com|10minutemail\.com|yopmail\.com|trashmail\.com)$)(?:[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}|(?:\[(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]:.+)])$/;
const handleSubmit = async (event) => { const handleSubmit = async (event) => {
event.preventDefault(); event.preventDefault();
const email = String(event.target.email.value || "").trim();
if (!emailRegex.test(email)) {
setEmailError(t("account:invalid-email-address-errormsg"));
setButtonDisabled(false);
return;
}
setEmailError("");
setButtonDisabled(true); setButtonDisabled(true);
try { try {
const email = String(event.target.email.value || "").trim();
const currentLocale = lang === "cy" ? "cy" : "en"; const currentLocale = lang === "cy" ? "cy" : "en";
const response = await fetch("/api/auth/resolve-locale", { const response = await fetch("/api/auth/resolve-locale", {
@@ -103,7 +115,9 @@ const SignIn = (props) => {
action="/api/auth/signin/email" action="/api/auth/signin/email"
onSubmit={handleSubmit} onSubmit={handleSubmit}
> >
<div className="govuk-form-group "> <div
className={`govuk-form-group${emailError ? " govuk-form-group--error" : ""}`}
>
<input <input
className="govuk-input" className="govuk-input"
name="csrfToken" name="csrfToken"
@@ -113,7 +127,6 @@ const SignIn = (props) => {
} }
/> />
<input <input
className="govuk-input"
name="callbackUrl" name="callbackUrl"
type="hidden" type="hidden"
defaultValue={ defaultValue={
@@ -130,7 +143,6 @@ const SignIn = (props) => {
: "en" : "en"
} }
/> />
<label <label
className="govuk-label" className="govuk-label"
htmlFor="email" htmlFor="email"
@@ -139,12 +151,28 @@ const SignIn = (props) => {
"auth:auth-email-label" "auth:auth-email-label"
)} )}
</label> </label>
{emailError ? (
<span
id="email-error"
className="govuk-error-message"
>
<span className="govuk-visually-hidden">
Error:
</span>{" "}
{emailError}
</span>
) : null}
<input <input
className="govuk-input govuk-!-width-three-quarters" className={`govuk-input govuk-!-width-three-quarters${emailError ? " govuk-input--error" : ""}`}
type="email" type="email"
id="email" id="email"
name="email" name="email"
aria-describedby={
emailError
? "email-error"
: undefined
}
/> />
</div> </div>
<div className="govuk-form-group"> <div className="govuk-form-group">
+1 -1
View File
@@ -307,7 +307,7 @@ let ContactUs = (props) => {
value ? undefined : t("newappeal:is-required-label"); value ? undefined : t("newappeal:is-required-label");
const emailRegex = const emailRegex =
/^(?:[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}|(?:\[(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]:.+)])$/; /^(?!.*(?:.+\.)?(?:burpcollaborator\.net|interactsh\.com|mailinator\.com|10minutemail\.com|yopmail\.com|trashmail\.com)$)(?:[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}|(?:\[(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]:.+)])$/;
const email = (value) => const email = (value) =>
value && !emailRegex.test(value) value && !emailRegex.test(value)
+2 -1
View File
@@ -18,6 +18,7 @@ import {
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createCRMTask } from "../../actions/services/integrationService"; import { createCRMTask } from "../../actions/services/integrationService";
import { sendEmail } from "../../actions/services/notifyService"; import { sendEmail } from "../../actions/services/notifyService";
import { wrapper } from "../../store/store";
import { useState } from "react"; import { useState } from "react";
@@ -306,7 +307,7 @@ let ContactUs = (props) => {
value ? undefined : t("newappeal:is-required-label"); value ? undefined : t("newappeal:is-required-label");
const emailRegex = const emailRegex =
/^(?:[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}|(?:\[(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]:.+)])$/; /^(?!.*(?:.+\.)?(?:burpcollaborator\.net|interactsh\.com|mailinator\.com|10minutemail\.com|yopmail\.com|trashmail\.com)$)(?:[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}|(?:\[(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]:.+)])$/;
const email = (value) => const email = (value) =>
value && !emailRegex.test(value) value && !emailRegex.test(value)
+31
View File
@@ -0,0 +1,31 @@
import { defineConfig } from "@playwright/test";
import dotenv from "dotenv";
const isCI = !!process.env.CI;
// Load .env silently in CI to avoid logs
dotenv.config({ debug: !isCI });
export default defineConfig({
testDir: "./pwe2e/tests",
timeout: 180000,
retries: isCI ? 1 : 0,
projects: [
{
name: "chromium",
timeout: 180000,
use: {
browserName: "chromium",
headless: isCI,
baseURL: process.env.BASE_URL || "http://localhost:3000",
screenshot: "only-on-failure",
video: "retain-on-failure",
trace: "retain-on-failure"
}
}
],
reporter: [
["html", { open: isCI ? "never" : "on-failure" }],
["junit", { outputFile: "test-results/results.xml" }]
]
});
+82
View File
@@ -0,0 +1,82 @@
import { test, expect } from "@playwright/test";
// TO DO - build PEDW API playwright harness
// Define a base URL for the mock API
const BASE_URL = process.env.BASE_URL;
test.describe("User API Validation Suite", () => {
// 1. GET Request Example
test("should fetch a list of users and validate headers", async ({
request,
}) => {
const response = await request.get(`${BASE_URL}/users/1`);
// Assert the HTTP status code is 200 OK
expect(response.ok()).toBeTruthy();
expect(response.status()).toBe(200);
// Parse the JSON response body
const responseBody = await response.json();
// Assert specific data fields inside the JSON
expect(responseBody.id).toBe(1);
expect(responseBody.name).toBe("Leanne Graham");
expect(responseBody.email).toBe("Sincere@april.biz");
// Assert response headers
expect(response.headers()["content-type"]).toContain("application/json");
});
// 2. POST Request Example
test("should successfully create a new post", async ({ request }) => {
const response = await request.post(`${BASE_URL}/posts`, {
headers: {
"Content-type": "application/json; charset=UTF-8",
// 'Authorization': `Bearer ${process.env.API_TOKEN}` <-- Example for CI/CD tokens
},
data: {
title: "Automation Test",
body: "Testing APIs with Playwright in DevOps pipelines.",
userId: 99,
},
});
// Assert creation status code (201 Created)
expect(response.status()).toBe(201);
const responseBody = await response.json();
// Assert the API returned our sent data with a new generated ID
expect(responseBody).toMatchObject({
title: "Automation Test",
body: "Testing APIs with Playwright in DevOps pipelines.",
userId: 99,
id: 101, // Mock database increments ID to 101
});
});
// 3. PUT Request Example (Update)
test("should update an existing post", async ({ request }) => {
const response = await request.put(`${BASE_URL}/posts/1`, {
data: {
id: 1,
title: "Updated Title",
body: "Updated body content",
userId: 1,
},
});
expect(response.ok()).toBeTruthy();
const responseBody = await response.json();
expect(responseBody.title).toBe("Updated Title");
});
// 4. DELETE Request Example
test("should delete a post", async ({ request }) => {
const response = await request.delete(`${BASE_URL}/posts/1`);
// Assert successful deletion response status
expect(response.status()).toBe(200);
});
});
+27
View File
@@ -0,0 +1,27 @@
import { test, expect } from "@playwright/test";
import { login } from "../../helpers";
test("Download a file when logged in", async ({ page }) => {
await login(page);
await page
.getByRole("textbox", { name: "Use the case reference or DNS" })
.click();
await page
.getByRole("textbox", { name: "Use the case reference or DNS" })
.fill("gaerwen");
await page.getByRole("button", { name: "Submit search" }).click();
// await page
// .getByRole("link", { name: "DNS3276735 - Gaerwen Wind Farm (test)" })
// .click();
await page.locator("dd a.govuk-link--no-underline").first().click();
const downloadPromise = page.waitForEvent("download");
await page.locator(".documentLink").first().click();
const download = await downloadPromise;
await page.getByText("Download complete!").click();
await page.getByRole("link", { name: "Home" }).click();
});
+149
View File
@@ -0,0 +1,149 @@
import { test, expect } from "@playwright/test";
import path from "path";
import { login } from "../../helpers";
const date = new Date();
date.setDate(date.getDate() - 1); // 👈 subtract 1 day
const day = date.getDate();
const ordinal = (n) => {
if (n > 3 && n < 21) return "th";
switch (n % 10) {
case 1:
return "st";
case 2:
return "nd";
case 3:
return "rd";
default:
return "th";
}
};
const weekday = date.toLocaleDateString("en-GB", { weekday: "long" });
const month = date.toLocaleDateString("en-GB", { month: "long" });
const finalDate = `${weekday}, ${month} ${day}${ordinal(day)}`;
test("Login and Raise new appeal", async ({ page }) => {
await login(page);
// create new appeal
await page.getByRole("link", { name: "Make a new appeal" }).click();
await page
.getByRole("textbox", { name: "Appellant or organisation's" })
.click();
await page
.getByRole("textbox", { name: "Appellant or organisation's" })
.fill("Bob");
await page.getByText("Appellant", { exact: true }).click();
await page.getByText("English").click();
await page.getByText("I confirm that I am making an").click();
await page.getByRole("button", { name: "Continue" }).click();
await page
.getByLabel("Select your Local Planning")
.selectOption("b9aee444-6ff0-eb11-aac7-00224800be9c");
await page.getByLabel("Select a case type").selectOption("846040000");
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("button", { name: "Continue" }).click();
const step2 = page.locator('[aria-controls="step-panel-appeal-details"]');
await step2.click();
await page.getByRole("textbox", { name: "Development description" }).click();
await page
.getByRole("textbox", { name: "Development description" })
.fill("Something in here");
await page.getByText("No", { exact: true }).click();
await page
.getByRole("textbox", { name: "LPA's application reference" })
.click();
await page
.getByRole("textbox", { name: "LPA's application reference" })
.fill("AB1234");
await page.getByRole("textbox", { name: "Application form dated" }).click();
await page.getByRole("option", { name: `Choose ${finalDate}` }).click();
await page.getByLabel("Reason for appeal").selectOption("846040005");
await page.getByRole("textbox", { name: "Site address line 1" }).click();
await page
.getByRole("textbox", { name: "Site address line 1" })
.fill("1 High Road");
await page.getByRole("textbox", { name: "Site address line 1" }).press("Tab");
await page.getByRole("textbox", { name: "Site address line 2" }).press("Tab");
await page
.getByRole("textbox", { name: "Site address town" })
.fill("Big town");
await page.getByRole("textbox", { name: "Site address town" }).press("Tab");
await page
.getByRole("textbox", { name: "Site address county" })
.fill("Cardiff");
await page.getByRole("textbox", { name: "Site address county" }).press("Tab");
await page
.getByRole("textbox", { name: "Site address postcode" })
.fill("cf21 3qa");
await page
.getByRole("textbox", { name: "Site address postcode" })
.press("Tab");
await page
.getByRole("textbox", { name: "Size of overall appeal site (" })
.fill("1");
await page
.getByRole("textbox", { name: "Size of overall appeal site (" })
.press("Tab");
await page
.getByRole("textbox", { name: "What is the area of floor" })
.fill("1");
await page
.getByRole("textbox", { name: "What is the area of floor" })
.press("Tab");
await page.getByRole("button", { name: "Continue" }).click();
await page.getByText("Certificate A - (for sole").click();
await page.getByText("(a) None of the land to which").click();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByText("No").first().click();
await page.getByText("No").nth(1).click();
await page.getByText("No").nth(2).click();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByText("No").first().click();
await page.getByRole("button", { name: "Continue" }).click();
// await page
// .getByRole("paragraph")
// .filter({ hasText: /^$/ })
// .click();
await page.locator(".ql-editor").fill("something here");
await page.getByText("No").nth(1).click();
await page
.getByLabel("What procedure would you like")
.selectOption("846040000");
await page.getByText("No").nth(3).click();
await page.getByText("No").nth(4).click();
await page.getByText("YesNo").nth(2).click();
await page.getByRole("button", { name: "Continue" }).click();
// upload files to statement of case
const files = [
path.resolve(__dirname, "../../testFiles/file1.pdf"),
path.resolve(__dirname, "../../testFiles/file2.pdf"),
];
const fileInput = page.locator("#pinswg_fileUpload");
await fileInput.setInputFiles(files);
const uploadedFiles = page.locator("h4", { hasText: "Uploaded files" });
await expect(uploadedFiles).toBeVisible({ timeout: 60000 });
await page.getByRole("button", { name: "Submit" }).click();
await page
.getByRole("checkbox", { name: "I wish to download a copy of the form" })
.check();
await page
.getByRole("checkbox", { name: "I confirm that all sections" })
.check();
await page.getByText("Submit appeal").click();
await page.getByRole("link", { name: "Home" }).click();
await page.goto("/");
await page.waitForTimeout(20000);
});
+729
View File
@@ -0,0 +1,729 @@
import { test, expect } from "@playwright/test";
import {
login,
loginAgent,
generatePlanningText,
loginLPA,
loginIP,
} from "../../helpers";
import path from "path";
const today = new Date();
// Add ordinal (st, nd, rd, th)
const day = today.getDate();
const ordinal = (n) => {
if (n > 3 && n < 21) return "th";
switch (n % 10) {
case 1:
return "st";
case 2:
return "nd";
case 3:
return "rd";
default:
return "th";
}
};
const weekday = today.toLocaleDateString("en-GB", { weekday: "long" });
const month = today.toLocaleDateString("en-GB", { month: "long" });
const finalDate = `${weekday}, ${month} ${day}${ordinal(day)}`;
const finalCommentsCase = process.env.FINAL_COMMENTS;
const statementCase = process.env.STATEMENT;
const questionnaireCase = process.env.QUESTIONNAIRE;
const consultationCase = process.env.CONSULTATION;
test("Raise Final Comments representation as an Appellant", async ({
page,
}) => {
await login(page);
await page.getByRole("textbox", { name: "Use the case reference" }).click();
console.log("Value to fill:", finalCommentsCase);
await page
.getByRole("textbox", { name: "Use the case reference" })
.fill(finalCommentsCase);
await page.getByRole("button", { name: "Submit search" }).click();
// await page
// .getByRole("link", { name: "DNS3276735 - Gaerwen Wind Farm (test)" })
// .click();
await page.locator("dd a.govuk-link--no-underline").first().click();
await page.getByRole("link", { name: "Make representation" }).click();
await page.getByRole("radio", { name: "Appellant" }).check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("radio", { name: "Final comments" }).check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("paragraph").filter({ hasText: /^$/ }).click();
await page
.getByRole("group")
.locator("div")
.filter({ hasText: "Please note that all" })
.locator("div")
.nth(3)
.fill("s");
await page
.locator("div")
.filter({ hasText: /^s$/ })
.nth(2)
.fill("some text to go here.....");
const files = [
path.resolve(__dirname, "../../testFiles/file1.pdf"),
path.resolve(__dirname, "../../testFiles/file2.pdf"),
];
const fileInput = page.locator("#representationDocuments");
await fileInput.setInputFiles(files);
const uploadedFiles = page.locator("h4", { hasText: "Uploaded files" });
await expect(uploadedFiles).toBeVisible({ timeout: 60000 });
await page.getByRole("button", { name: "Continue" }).click();
await page
.getByRole("checkbox", { name: "I confirm I have read the" })
.check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("link", { name: "Continue" }).click();
await page.goto("/");
await page.waitForTimeout(2000);
});
test("Raise Final Comments representation as an Interested Party", async ({
page,
}) => {
await loginIP(page);
//raise rep
await page.getByRole("textbox", { name: "Use the case reference" }).click();
await page
.getByRole("textbox", { name: "Use the case reference" })
.fill(finalCommentsCase);
await page.getByRole("button", { name: "Submit search" }).click();
await page.locator("dd a.govuk-link--no-underline").first().click();
await page.getByRole("link", { name: "Make representation" }).click();
await page.getByRole("radio", { name: "Interested Party" }).check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("radio", { name: "Final comments" }).check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByText("Yes").click();
await page
.getByRole("textbox", { name: "Enter the name of the company" })
.click();
await page
.getByRole("textbox", { name: "Enter the name of the company" })
.fill("Big Company");
await page.getByRole("paragraph").filter({ hasText: /^$/ }).click();
await page.locator(".ql-editor").fill(generatePlanningText(5));
const files = [
path.resolve(__dirname, "../../testFiles/file1.pdf"),
path.resolve(__dirname, "../../testFiles/file2.pdf"),
];
const fileInput = page.locator("#representationDocuments");
await fileInput.setInputFiles(files);
const uploadedFiles = page.locator("h4", { hasText: "Uploaded files" });
await expect(uploadedFiles).toBeVisible({ timeout: 60000 });
await page.getByRole("button", { name: "Continue" }).click();
await page
.getByRole("checkbox", { name: "I confirm I have read the" })
.check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("link", { name: "Continue" }).click();
await page.goto("/");
await page.waitForTimeout(2000);
});
test("Raise Statement representation as an Interested Party", async ({
page,
}) => {
await loginIP(page);
//raise rep
await page.getByRole("textbox", { name: "Use the case reference" }).click();
await page
.getByRole("textbox", { name: "Use the case reference" })
.fill(statementCase);
await page.getByRole("button", { name: "Submit search" }).click();
await page.locator("dd a.govuk-link--no-underline").first().click();
await page.getByRole("link", { name: "Make representation" }).click();
await page.getByRole("radio", { name: "Interested Party" }).check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("radio", { name: "Statement" }).check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByText("Yes").click();
await page
.getByRole("textbox", { name: "Enter the name of the company" })
.click();
await page
.getByRole("textbox", { name: "Enter the name of the company" })
.fill("Big Company");
await page.getByRole("paragraph").filter({ hasText: /^$/ }).click();
await page.locator(".ql-editor").fill(generatePlanningText(5));
const files = [
path.resolve(__dirname, "../../testFiles/file1.pdf"),
path.resolve(__dirname, "../../testFiles/file2.pdf"),
];
const fileInput = page.locator("#representationDocuments");
await fileInput.setInputFiles(files);
const uploadedFiles = page.locator("h4", { hasText: "Uploaded files" });
await expect(uploadedFiles).toBeVisible({ timeout: 60000 });
await page.getByRole("button", { name: "Continue" }).click();
await page
.getByRole("checkbox", { name: "I confirm I have read the" })
.check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("link", { name: "Continue" }).click();
await page.goto("/");
await page.waitForTimeout(2000);
});
test("Raise Consultation Response as an Interested Party", async ({ page }) => {
await loginIP(page);
//raise rep
await page.getByRole("textbox", { name: "Use the case reference" }).click();
await page
.getByRole("textbox", { name: "Use the case reference" })
.fill(consultationCase);
await page.getByRole("button", { name: "Submit search" }).click();
await page.locator("dd a.govuk-link--no-underline").first().click();
await page
.getByRole("link", { name: "Submit a Consultation Response" })
.click();
await page.getByRole("radio", { name: "Interested Party" }).check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("radio", { name: "Consultation Response" }).check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByText("Yes").click();
await page
.getByRole("textbox", { name: "Enter the name of the company" })
.click();
await page
.getByRole("textbox", { name: "Enter the name of the company" })
.fill("Big Company");
await page.getByRole("paragraph").filter({ hasText: /^$/ }).click();
await page.locator(".ql-editor").fill(generatePlanningText(5));
const files = [
path.resolve(__dirname, "../../testFiles/file1.pdf"),
path.resolve(__dirname, "../../testFiles/file2.pdf"),
];
const fileInput = page.locator("#representationDocuments");
await fileInput.setInputFiles(files);
const uploadedFiles = page.locator("h4", { hasText: "Uploaded files" });
await expect(uploadedFiles).toBeVisible({ timeout: 60000 });
await page.getByRole("button", { name: "Continue" }).click();
await page
.getByRole("checkbox", { name: "I confirm I have read the" })
.check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("link", { name: "Continue" }).click();
await page.goto("/");
await page.waitForTimeout(2000);
});
test("Raise LIR as an Interested Party", async ({ page }) => {
await loginIP(page);
//raise rep
await page.getByRole("textbox", { name: "Use the case reference" }).click();
await page
.getByRole("textbox", { name: "Use the case reference" })
.fill(consultationCase);
await page.getByRole("button", { name: "Submit search" }).click();
await page.locator("dd a.govuk-link--no-underline").first().click();
await page
.getByRole("link", { name: "Submit a Consultation Response" })
.click();
await page.getByRole("radio", { name: "Interested Party" }).check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("radio", { name: "Local Impact Report" }).check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByText("Yes").click();
await page
.getByRole("textbox", { name: "Enter the name of the company" })
.click();
await page
.getByRole("textbox", { name: "Enter the name of the company" })
.fill("Big Company");
const files = [
path.resolve(__dirname, "../../testFiles/file1.pdf"),
path.resolve(__dirname, "../../testFiles/file2.pdf"),
];
const fileInput = page.locator("#representationDocuments");
await fileInput.setInputFiles(files);
const uploadedFiles = page.locator("h4", { hasText: "Uploaded files" });
await expect(uploadedFiles).toBeVisible({ timeout: 60000 });
await page.getByRole("button", { name: "Continue" }).click();
await page
.getByRole("checkbox", { name: "I confirm I have read the" })
.check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("link", { name: "Continue" }).click();
await page.goto("/");
await page.waitForTimeout(2000);
});
test("Raise MIR as an Interested Party", async ({ page }) => {
await loginIP(page);
//raise rep
await page.getByRole("textbox", { name: "Use the case reference" }).click();
await page
.getByRole("textbox", { name: "Use the case reference" })
.fill(consultationCase);
await page.getByRole("button", { name: "Submit search" }).click();
await page.locator("dd a.govuk-link--no-underline").first().click();
await page
.getByRole("link", { name: "Submit a Consultation Response" })
.click();
await page.getByRole("radio", { name: "Interested Party" }).check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("radio", { name: "Marine Impact Report" }).check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByText("Yes").click();
await page
.getByRole("textbox", { name: "Enter the name of the company" })
.click();
await page
.getByRole("textbox", { name: "Enter the name of the company" })
.fill("Big Company");
const files = [
path.resolve(__dirname, "../../testFiles/file1.pdf"),
path.resolve(__dirname, "../../testFiles/file2.pdf"),
];
const fileInput = page.locator("#representationDocuments");
await fileInput.setInputFiles(files);
const uploadedFiles = page.locator("h4", { hasText: "Uploaded files" });
await expect(uploadedFiles).toBeVisible({ timeout: 60000 });
await page.getByRole("button", { name: "Continue" }).click();
await page
.getByRole("checkbox", { name: "I confirm I have read the" })
.check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("link", { name: "Continue" }).click();
await page.goto("/");
await page.waitForTimeout(2000);
});
test("Raise Final Comments representation as an Agent", async ({ page }) => {
await loginAgent(page);
//raise rep
const acceptButton = page.getByRole("button", { name: "Accept cookies" });
if (await acceptButton.isVisible()) {
await acceptButton.click();
}
await page.getByRole("textbox", { name: "Use the case reference" }).click();
await page
.getByRole("textbox", { name: "Use the case reference" })
.fill(finalCommentsCase);
await page.getByRole("button", { name: "Submit search" }).click();
await page.locator("dd a.govuk-link--no-underline").first().click();
await page.getByRole("link", { name: "Make representation" }).click();
await page.getByRole("radio", { name: "Agent" }).check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("radio", { name: "Final comments" }).check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByText("Yes").click();
await page
.getByRole("textbox", { name: "Enter the name of the company" })
.click();
await page
.getByRole("textbox", { name: "Enter the name of the company" })
.fill("Big Company");
await page.getByRole("paragraph").filter({ hasText: /^$/ }).click();
await page.locator(".ql-editor").fill(generatePlanningText(4));
const files = [
path.resolve(__dirname, "../../testFiles/file1.pdf"),
path.resolve(__dirname, "../../testFiles/file2.pdf"),
];
const fileInput = page.locator("#representationDocuments");
await fileInput.setInputFiles(files);
const uploadedFiles = page.locator("h4", { hasText: "Uploaded files" });
await expect(uploadedFiles).toBeVisible({ timeout: 60000 });
await page.getByRole("button", { name: "Continue" }).click();
await page
.getByRole("checkbox", { name: "I confirm I have read the" })
.check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("link", { name: "Continue" }).click();
await page.goto("/");
await page.waitForTimeout(2000);
});
test("Raise Statement representation as an Agent", async ({ page }) => {
await loginAgent(page);
//raise rep
await page.getByRole("textbox", { name: "Use the case reference" }).click();
await page
.getByRole("textbox", { name: "Use the case reference" })
.fill(statementCase);
await page.getByRole("button", { name: "Submit search" }).click();
await page.locator("dd a.govuk-link--no-underline").first().click();
await page.getByRole("link", { name: "Make representation" }).click();
await page.getByRole("radio", { name: "Agent" }).check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("radio", { name: "Statement" }).check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByText("Yes").click();
await page
.getByRole("textbox", { name: "Enter the name of the company" })
.click();
await page
.getByRole("textbox", { name: "Enter the name of the company" })
.fill("Big Company");
await page.getByRole("paragraph").filter({ hasText: /^$/ }).click();
await page.locator(".ql-editor").fill(generatePlanningText(5));
const files = [
path.resolve(__dirname, "../../testFiles/file1.pdf"),
path.resolve(__dirname, "../../testFiles/file2.pdf"),
];
const fileInput = page.locator("#representationDocuments");
await fileInput.setInputFiles(files);
const uploadedFiles = page.locator("h4", { hasText: "Uploaded files" });
await expect(uploadedFiles).toBeVisible({ timeout: 60000 });
await page.getByRole("button", { name: "Continue" }).click();
await page
.getByRole("checkbox", { name: "I confirm I have read the" })
.check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("link", { name: "Continue" }).click();
await page.goto("/");
await page.waitForTimeout(2000);
});
test("Raise questionnaire as an LPA", async ({ page }) => {
await loginLPA(page);
await page.getByRole("textbox", { name: "Use the case reference" }).click();
await page
.getByRole("textbox", { name: "Use the case reference" })
.fill(questionnaireCase);
await page.getByRole("textbox", { name: "Use the case reference," }).click();
await page
.getByRole("textbox", { name: "Use the case reference," })
.fill(questionnaireCase);
await page.getByRole("button", { name: "Submit Search" }).click();
await page.getByRole("link", { name: questionnaireCase }).click();
// await page.getByRole("button", { name: "Submit search" }).click();
//await page.locator("dd a.govuk-link--no-underline").first().click();
await page.getByRole("link", { name: "Make representation" }).click();
await page.getByRole("radio", { name: "Questionnaire" }).check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("combobox").selectOption("Written representations");
await page.getByText("No").first().click();
await page.getByText("No").nth(1).click();
await page.getByText("No").nth(2).click();
await page.getByText("Yes").nth(2).click();
await page.getByText("No").nth(3).click();
await page.getByRole("paragraph").filter({ hasText: /^$/ }).click();
// await page.locator(".ql-editor").fill(generatePlanningText(2));
// await page
// .locator("div")
// .filter({ hasText: /^w$/ })
// .nth(2)
// .fill(generatePlanningText(2));
await page.getByRole("button", { name: "Continue" }).click();
await page.locator(".ql-editor").first().fill(generatePlanningText(2));
await page.locator(".ql-editor").nth(1).fill(generatePlanningText(2));
await page.locator(".ql-editor").nth(2).fill(generatePlanningText(2));
// // await page.getByRole("paragraph").nth(4).click();
// await page
// .locator(".ql-editor.ql-blank")
// .first()
// .fill(generatePlanningText(2));
// await page.getByRole("paragraph").filter({ hasText: /^$/ }).click();
// await page
// .locator(".ql-editor.ql-blank")
// .first()
// .fill(generatePlanningText(2));
// await page.locator(".ql-editor.ql-blank").fill("w e");
// await page
// .locator("div")
// .filter({ hasText: /^w e$/ })
// .nth(2)
// .fill(generatePlanningText(2));
// await page.getByRole("paragraph").filter({ hasText: /^$/ }).click();
// await page
// .locator("div")
// .filter({ hasText: /^w e$/ })
// .nth(2)
// .fill(generatePlanningText(2));
await page.getByText("No", { exact: true }).first().click();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByText("No").first().click();
await page.getByText("No").nth(1).click();
await page.getByText("No").nth(2).click();
await page.getByText("No").nth(3).click();
await page.getByText("No").nth(4).click();
await page.getByText("No").nth(5).click();
await page
.locator(
"div:nth-child(8) > .govuk-form-group > .govuk-fieldset > .govuk-radios > div:nth-child(2) > .govuk-radios__item > .govuk-label",
)
.click();
await page
.locator(
"div:nth-child(9) > .govuk-fieldset > .govuk-radios > div:nth-child(2) > .govuk-label",
)
.click();
await page
.locator(
"div:nth-child(10) > .govuk-form-group > .govuk-fieldset > .govuk-radios > div:nth-child(2) > .govuk-radios__item > .govuk-label",
)
.click();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByText("No").nth(2).click();
await page.getByText("No").nth(3).click();
await page.getByText("No").nth(5).click();
await page.getByText("No", { exact: true }).nth(3).click();
await page.getByText("No", { exact: true }).nth(4).click();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByText("Yes").first().click();
await page.getByText("Yes").nth(1).click();
await page.getByText("No", { exact: true }).nth(2).click();
await page.getByText("Yes").nth(2).click();
await page.getByText("No", { exact: true }).nth(3).click();
await page.getByText("No", { exact: true }).nth(4).click();
await page.getByText("No", { exact: true }).nth(5).click();
await page
.locator(
"div:nth-child(9) > .govuk-form-group > .govuk-fieldset > .govuk-radios > div:nth-child(2) > .govuk-radios__item > .govuk-label",
)
.click();
await page
.locator(
"div:nth-child(10) > .govuk-form-group > .govuk-fieldset > .govuk-radios > div:nth-child(2) > .govuk-radios__item > .govuk-label",
)
.click();
await page.getByRole("button", { name: "Continue" }).click();
// await page.getByText("Drag and drop your files here").click();
const files = [
path.resolve(__dirname, "../../testFiles/file1.pdf"),
path.resolve(__dirname, "../../testFiles/file2.pdf"),
];
const fileInput = page.locator("#representationDocuments");
await fileInput.setInputFiles(files);
const uploadedFiles = page.locator("h4", { hasText: "Uploaded files" });
await expect(uploadedFiles).toBeVisible({ timeout: 60000 });
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("textbox", { name: "Signed" }).click();
await page.getByRole("textbox", { name: "Signed" }).fill("Bob Bob");
await page.getByRole("textbox", { name: "Date" }).click();
await page.getByRole("option", { name: `Choose ${finalDate}` }).click();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByText("I wish to download a copy of").click();
await page
.getByRole("checkbox", { name: "I confirm I have read the" })
.check();
const downloadPromise = page.waitForEvent("download");
await page.getByRole("button", { name: "Continue" }).click();
const download = await downloadPromise;
await page.getByRole("link", { name: "Continue" }).click();
await page.goto("/");
await page.waitForTimeout(2000);
});
test("Raise Statement representation as an LPA", async ({ page }) => {
await loginLPA(page);
//raise rep
await page.getByRole("textbox", { name: "Use the case reference" }).click();
await page
.getByRole("textbox", { name: "Use the case reference" })
.fill(statementCase);
await page.getByRole("button", { name: "Submit search" }).click();
await page.locator("dd a.govuk-link--no-underline").first().click();
await page.getByRole("link", { name: "Make representation" }).click();
await page.getByRole("radio", { name: "Statement" }).check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("paragraph").filter({ hasText: /^$/ }).click();
await page.locator(".ql-editor").fill(generatePlanningText(5));
const files = [
path.resolve(__dirname, "../../testFiles/file1.pdf"),
path.resolve(__dirname, "../../testFiles/file2.pdf"),
];
const fileInput = page.locator("#representationDocuments");
await fileInput.setInputFiles(files);
const uploadedFiles = page.locator("h4", { hasText: "Uploaded files" });
await expect(uploadedFiles).toBeVisible({ timeout: 60000 });
await page.getByRole("button", { name: "Continue" }).click();
await page
.getByRole("checkbox", { name: "I confirm I have read the" })
.check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("link", { name: "Continue" }).click();
await page.goto("/");
await page.waitForTimeout(2000);
});
test("Raise LIR as an LPA", async ({ page }) => {
await loginLPA(page);
//raise rep
await page.getByRole("textbox", { name: "Use the case reference" }).click();
await page
.getByRole("textbox", { name: "Use the case reference" })
.fill(consultationCase);
await page.getByRole("button", { name: "Submit search" }).click();
await page.locator("dd a.govuk-link--no-underline").first().click();
await page
.getByRole("link", { name: "Submit a Consultation Response" })
.click();
await page.getByRole("radio", { name: "Local Impact Report" }).check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("paragraph").filter({ hasText: /^$/ }).click();
await page.locator(".ql-editor").fill(generatePlanningText(5));
const files = [
path.resolve(__dirname, "../../testFiles/file1.pdf"),
path.resolve(__dirname, "../../testFiles/file2.pdf"),
];
const fileInput = page.locator("#representationDocuments");
await fileInput.setInputFiles(files);
const uploadedFiles = page.locator("h4", { hasText: "Uploaded files" });
await expect(uploadedFiles).toBeVisible({ timeout: 60000 });
await page.getByRole("button", { name: "Continue" }).click();
await page
.getByRole("checkbox", { name: "I confirm I have read the" })
.check();
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("link", { name: "Continue" }).click();
await page.goto("/");
await page.waitForTimeout(2000);
});
test("Open Saved Rep as an Interested Party", async ({ page }) => {
await loginIP(page);
//raise rep
const firstCaseLink = page
.locator("#my-representations-card .govuk-link--no-underline")
.first();
await firstCaseLink.click();
await page.getByRole("button", { name: "Save and exit" }).click();
await page.goto("/");
await page.waitForTimeout(2000);
});
+377
View File
@@ -0,0 +1,377 @@
import { test, expect } from "@playwright/test";
import path from "path";
import * as XLSX from "xlsx";
import {
login,
fillYesNoConditional,
fillQuillEditor,
toDDMMYYYY,
} from "../../helpers";
const workbook = XLSX.readFile("./testFiles/newappeals_s78.xlsx");
const sheetName = workbook.SheetNames[0];
const data = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName], {
defval: "",
cellDates: true,
});
// console.log("sheetName :", sheetName);
// console.log("Loaded rows:", data);
data.forEach((row, index) => {
test(`Import new appeal for ${row["Appellant / Organisation"]}`, async ({
page,
}) => {
await login(page);
await page.getByRole("link", { name: "Make a new appeal" }).click();
await page
.getByRole("textbox", { name: "Appellant or organisation's" })
.click();
await page
.getByRole("textbox", { name: "Appellant or organisation's" })
.fill(row["Appellant / Organisation"]);
await page
.getByRole("radio", { name: row["Appellant / Agent Radio Button"] })
.click();
await page.locator("#pinswg_appellantfirstname").fill(row["First Name"]);
await page.locator("#pinswg_appellantlastname").fill(row["Last Name"]);
await page.locator("#pinswg_appellantaddress").fill(row["Address"]);
await page
.locator("#pinswg_appellantemailaddress")
.fill(row["Email Address"]);
await page
.locator("#pinswg_appellantphonenumber")
.fill(row["Telephone Number"]);
// Excel value: "English" or "Welsh"
const languageText = row["Language Preference Radio Button"]?.trim();
// Map Excel text to radio button value
const radioValueLang = languageText === "Welsh" ? "846040001" : "846040000";
// Select the radio by name and value
await page
.locator(
`input[name="pinswg_languagepreference"][value="${radioValueLang}"]`
)
.check();
if (row["Appellant / Agent Radio Button"] == "Agent") {
await page.locator("#pinswg_agentcompanyname").fill(row["Company Name"]);
await page
.locator("#pinswg_agentreference")
.fill(row["Agent's Reference"]);
await page.locator("#pinswg_agentfirstname").fill(row["First Name_1"]);
await page.locator("#pinswg_agentlastname").fill(row["Last Name_1"]);
await page.locator("#pinswg_agentaddress").fill(row["Address_1"]);
await page
.locator("#pinswg_agentemailaddress")
.fill(row["Email Address_1"]);
await page
.locator("#pinswg_agentphonenumber")
.fill(row["Telephone Number_1"]);
const agentLanguageText =
row["Agent Language Preference Radio Button"]?.trim();
const agentRadioValue =
agentLanguageText === "Welsh" ? "846040001" : "846040000";
await page
.locator(
`input[name="pinswg_agentlanguagepreference"][value="${agentRadioValue}"]`
)
.check();
}
await page.getByText("I confirm that I am making an").click();
await page.getByRole("button", { name: "Continue" }).click();
await page
.getByLabel("Select your Local Planning")
.selectOption({ label: row["Select LPA"] });
await page.getByLabel("Select a case type").selectOption("846040000");
await page.getByRole("button", { name: "Continue" }).click();
await page.getByRole("button", { name: "Continue" }).click();
const step2 = page.locator('[aria-controls="step-panel-appeal-details"]');
await step2.click();
await page
.getByRole("textbox", { name: "Development description" })
.click();
await page
.getByRole("textbox", { name: "Development description" })
.fill(row["Development Description"]);
await page.getByText("No", { exact: true }).click();
await page
.getByRole("textbox", { name: "LPA's application reference" })
.fill(row["LPA's Application Ref Num"]);
await page
.locator("#pinswg_dateofapplication")
.fill(toDDMMYYYY(row["App Form Dated"]));
await page
.getByLabel("Reason for appeal")
.selectOption({ label: row["Reason for Appeal"] });
await page.getByRole("textbox", { name: "Site address line 1" }).click();
await page
.getByRole("textbox", { name: "Site address line 1" })
.fill(row["Site Address Line 1"]);
await page
.getByRole("textbox", { name: "Site address line 2" })
.fill(row["Site Address Line 2"]);
await page
.getByRole("textbox", { name: "Site address town" })
.fill(row["Site Address Town"]);
await page
.getByRole("textbox", { name: "Site address county" })
.fill(row["Site Address County"]);
await page
.getByRole("textbox", { name: "Site address postcode" })
.fill(row["Site Address Postcode"]);
await page
.getByRole("textbox", { name: "Size of overall appeal site (" })
.fill(String(row["Size of Overall Appeal Site"]));
await page
.getByRole("textbox", { name: "What is the area of floor" })
.fill(String(row["Floor Space (Sq Metres)"]));
await page.getByRole("button", { name: "Continue" }).click();
// Ownership Certificate selection and conditional fields
const ownershipMap = {
"Certificate A": "846040001",
"Certificate B": "846040002",
"Certificate C": "846040003",
"Certificate D": "846040003", // C and D share same option
};
const cert = row["Ownership Certificate"]?.trim();
const value = ownershipMap[cert];
if (!value) throw new Error(`Unknown ownership certificate: ${cert}`);
// Select the certificate radio
await page
.locator(`input[name="pinswg_ownershipcertificate"][value="${value}"]`)
.check();
// Conditional fields for Certificate B
if (cert === "Certificate B") {
// Wait for Owner Name input to appear (dynamic rendering)
const ownerInput = page.locator(
'input[id^="pinswg_owners"][id$=".pinswg_owners"]'
);
await ownerInput.waitFor({ state: "visible", timeout: 5000 });
await ownerInput.fill(row["Owner Name"] || "");
// Wait for Date Served input to appear
const dateServedInput = page.locator(
".react-datepicker__input-container input"
);
await dateServedInput.waitFor({ state: "visible", timeout: 5000 });
await dateServedInput.fill(toDDMMYYYY(row["Date Served"]) || "");
}
// Ownership Certificate selection and conditional fields
const agHoldingMap = {
"(a)": "846040002",
"(b) (i)": "846040001",
"(b) (ii)": "846040000",
};
const agriculturalHolding = row["Agricultural Holding"]?.trim();
const agValue = agHoldingMap[agriculturalHolding];
if (!agValue) throw new Error(`Unknown ownership certificate: ${cert}`);
// Select the certificate radio
await page
.locator(`input[name="pinswg_agriculturalholding"][value="${agValue}"]`)
.check();
// Conditional fields for b (ii)
if (agriculturalHolding === "(b) (ii)") {
// Wait for Owner Name input to appear (dynamic rendering)
const tenantInput = page.locator(
'input[id^="pinswg_agriculturaltenantname"][id$=".pinswg_agriculturaltenantname"]'
);
await tenantInput.waitFor({ state: "visible", timeout: 5000 });
await tenantInput.fill(row["Tenant Name"] || "");
// Wait for Date Served input to appear
const dateServedInput = page.locator(
".react-datepicker__input-container input"
);
await dateServedInput.waitFor({ state: "visible", timeout: 5000 });
await dateServedInput.fill(toDDMMYYYY(row["Date Served_1"]) || "");
}
await page.getByRole("button", { name: "Continue" }).click();
// Site viewable from road
await fillYesNoConditional(
page,
"pinswg_siteviewablefromroad",
row["See Relevant Parts?"],
null,
null
);
// Inspector needed on site
await fillYesNoConditional(
page,
"pinswg_inspectorneededonsite",
row["Essential to Enter?"],
"#pinswg_whyisinspectorneededonsite",
row["Please Explain (Enter)"]
);
// Health & safety issues
await fillYesNoConditional(
page,
"pinswg_healthandsafetyissuesonsite",
row["Any H&S Issues?"],
"#pinswg_outlinehealthandsafetyissuesonsite",
row["Set out H&S Issues"]
);
await page.getByRole("button", { name: "Continue" }).click();
// Step 5 Other Appeals
await fillYesNoConditional(
page,
"pinswg_additionalappealsmade", // radio name
row["Any Other Appeals?"], // "Y" or blank from Excel
"#pinswg_additionalappealsmadedetails", // Quill editor selector
row["Other Appeal Details"], // text to fill
false // flag that it's a Quill editor
);
await page.getByRole("button", { name: "Continue" }).click();
// Step 6 Submission of Case
// Q.1
const subnissionOfCaseInput = page.locator(".ql-editor");
await subnissionOfCaseInput.waitFor({ state: "visible", timeout: 100000 });
await subnissionOfCaseInput.fill(row["Submit Statement of Case"]);
// Q.2
const attachSocValue = (row["Attached Separate Case Doc?"] || "")
.trim()
.toUpperCase();
const radioValue = attachSocValue === "Y" ? "true" : "false";
// Select the radio
await page
.locator(`input[name="pinswg_attachsoc"][value="${radioValue}"]`)
.check();
// Q.3
const procedureValue = row["What Procedure?"]?.trim(); // e.g., "Written representation"
// Wait for the dropdown to appear
const procedureSelect = page.locator("#pinswg_procedure");
await procedureSelect.waitFor({ state: "visible", timeout: 5000 });
// Select by label (the visible text)
await procedureSelect.selectOption({ label: procedureValue });
// If not "Written representation", fill the explanation box
if (
procedureValue &&
procedureValue.toLowerCase() !== "written representation"
) {
const explanation =
row["Procedure Explanation"] ||
"Default explanation: A hearing/inquiry is required due to case complexity and witnesses.";
const textArea = page.locator("#pinswg_chosenprocedureexplanation");
await textArea.waitFor({ state: "visible", timeout: 5000 });
await textArea.fill(explanation);
}
// Q.4
await fillYesNoConditional(
page,
"pinswg_costappliedforindicator", // radio name
row["Cost Applied For"], // "Y" or blank from Excel
".ql-editor", // Quill editor selector
row["Cost Application"], // text to fill
true // flag that it's a Quill editor
);
// Q.5
await fillYesNoConditional(
page,
"pinswg_s106unilateralsubmitted", // radio name
row["Submit S106?"] // "Y" or blank from Excel
);
await page.getByRole("button", { name: "Continue" }).click();
// Step 7 Upload Documents
const files = [
path.resolve(__dirname, "../../testFiles/file1.pdf"),
path.resolve(__dirname, "../../testFiles/file2.pdf"),
];
const firstInputFiles = [
path.resolve(__dirname, "../../testFiles/file1.pdf"),
];
const fileInputs = [
"#pinswg_fileUpload",
"#pinswg_fileUpload1",
"#pinswg_fileUpload2",
"#pinswg_fileUpload3",
"#pinswg_fileUpload4",
"#pinswg_fileUpload5",
"#pinswg_fileUpload6",
"#pinswg_fileUpload7",
"#pinswg_fileUpload8",
"#pinswg_fileUpload9",
"#pinswg_fileUpload10",
"#pinswg_fileUpload11",
"#pinswg_fileUpload12",
"#pinswg_fileUpload13",
"#pinswg_fileUpload14",
"#pinswg_fileUpload15",
];
for (let i = 0; i < fileInputs.length; i++) {
const selector = fileInputs[i];
if (i === 0) {
// First input gets its specific files
await page.locator(selector).setInputFiles(firstInputFiles);
} else {
// All other inputs get the common files
await page.locator(selector).setInputFiles(files);
}
const uploadedFiles = page
.locator("h4", { hasText: "Uploaded files" })
.first();
await expect(uploadedFiles).toBeVisible({ timeout: 60000 });
}
await page.getByRole("button", { name: "Submit" }).click();
// Check and Confirm
await page
.getByRole("checkbox", { name: "I confirm that all sections" })
.check();
await page.getByText("Submit appeal").click();
await page.waitForTimeout(20000);
});
});
@@ -0,0 +1,26 @@
import { test, expect } from "@playwright/test";
test("Download a file", async ({ page }) => {
await page.goto("/");
await page.getByRole("button", { name: "Accept cookies" }).click();
await page
.getByRole("textbox", { name: "Use the case reference or DNS" })
.click();
await page
.getByRole("textbox", { name: "Use the case reference or DNS" })
.fill("gaerwen");
await page.getByRole("button", { name: "Submit search" }).click();
// await page
// .getByRole("link", { name: "DNS3276735 - Gaerwen Wind Farm (test)" })
// .click();
await page.locator("dd a.govuk-link--no-underline").first().click();
const downloadPromise = page.waitForEvent("download");
await page.locator(".documentLink").first().click();
const download = await downloadPromise;
await page.getByText("Download complete!").click();
await page.getByRole("link", { name: "Home" }).click();
});
@@ -0,0 +1,35 @@
import { test, expect } from "@playwright/test";
import { handleSearchResults } from "../../helpers/index";
test("Check for DNS applications", async ({ page }) => {
await page.goto("/");
await page.getByRole("button", { name: "Accept cookies" }).click();
await page.getByRole("link", { name: "View all DNS applications" }).click();
async function handleSearchResults(page) {
const results = page.locator("dd a.govuk-link--no-underline");
await Promise.race([
results.first().waitFor({ state: "visible", timeout: 15000 }),
]);
if ((await results.count()) > 0) {
await results.first().click({ timeout: 15000 });
await expect(page.locator("#main-content")).toContainText("Reference:", {
timeout: 15000,
});
return "clicked";
} else if ((await noResultsMessage.count()) > 0) {
console.log("️ No results found. Test passes.");
return "no-results";
} else {
throw new Error(
"⚠️ Unexpected search page state: neither results nor zero-results message found."
);
}
}
// Handle search results safely
const outcome = await handleSearchResults(page);
console.log(`Search outcome for DNS":`, outcome);
});
+208
View File
@@ -0,0 +1,208 @@
import { test, expect } from "@playwright/test";
import * as XLSX from "xlsx";
import { handleSearchResults } from "../../helpers/index";
test.use({ headless: true });
test("Basic search", async ({ page }) => {
await page.goto("/");
await page.getByRole("button", { name: "Accept cookies" }).click();
await page
.getByRole("textbox", { name: "Use the case reference or DNS" })
.click();
await page
.getByRole("textbox", { name: "Use the case reference or DNS" })
.fill("cas-");
await page.getByRole("button", { name: "Submit search" }).click();
// Handle search results safely
const outcome = await handleSearchResults(page);
console.log(`Search outcome for basic search":`, outcome);
});
const workbook = XLSX.readFile("./testFiles/appealList.xlsx");
const sheetName = workbook.SheetNames[0];
const rawData = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName], {
defval: "",
});
const data = rawData
.map((row) => ({
Values: row["Values"]?.trim(),
AppealTypes: row["AppealType"]?.trim(),
}))
.filter((r) => r.Values && r.AppealTypes);
test.describe("Advanced Search Appeal Types", () => {
if (data.length === 0) {
test("No data found in spreadsheet", async () => {
console.warn("No valid rows found in appealList.xlsx");
});
}
data.forEach((row, index) => {
test(`Advanced search - ${row.AppealTypes} #${index + 1}`, async ({
page,
}) => {
await page.goto("/");
const acceptButton = page.getByRole("button", { name: "Accept cookies" });
if (await acceptButton.isVisible()) await acceptButton.click();
await page.getByRole("link", { name: "Advanced search" }).click();
await page.getByLabel("Select a case type").selectOption(row.Values);
await page.getByRole("button", { name: "Search" }).click();
// Handle search results safely
const outcome = await handleSearchResults(page);
console.log(`Search outcome for "${row.AppealTypes}":`, outcome);
});
});
});
const sheetName2 = workbook.SheetNames[1];
const rawData2 = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName2], {
defval: "",
});
const data2 = rawData2
.map((row) => ({
Values: row["Values"]?.trim(),
LPA: row["LPA"]?.trim(),
}))
.filter((r) => r.Values && r.LPA);
test.describe("Advanced Search LPA", () => {
if (data2.length === 0) {
test("No data found in spreadsheet", async () => {
console.warn("⚠️ No valid rows found in lpaList.xlsx");
});
}
data2.forEach((row, index) => {
test(`Advanced search LPA - ${row.LPA} #${index + 1}`, async ({ page }) => {
await page.goto("/");
const acceptButton = page.getByRole("button", { name: "Accept cookies" });
if (await acceptButton.isVisible()) await acceptButton.click();
await page.getByRole("link", { name: "Advanced search" }).click();
await page
.getByLabel("Local Planning Authority")
.selectOption(row.Values);
await page.getByRole("button", { name: "Search" }).click();
// Handle search results safely
const outcome = await handleSearchResults(page);
console.log(`Search outcome for "${row.LPA}":`, outcome);
});
});
});
const sheetName3 = workbook.SheetNames[2];
const rawData3 = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName3], {
defval: "",
});
const data3 = rawData3
.map((row) => ({
Values: row["Values"],
Status: row["Status"]?.trim(),
}))
.filter((r) => r.Values && r.Status);
test.describe("Advanced Search Case Status", () => {
if (data3.length === 0) {
test("No data found in spreadsheet", async () => {
console.warn("⚠️ No valid rows found in lpaList.xlsx");
});
}
data3.forEach((row, index) => {
test(`Advanced search Case Status - ${row.Status} #${index + 1}`, async ({
page,
}) => {
await page.goto("/");
const acceptButton = page.getByRole("button", { name: "Accept cookies" });
if (await acceptButton.isVisible()) await acceptButton.click();
await page.getByRole("link", { name: "Advanced search" }).click();
await page.getByLabel("Case Status").selectOption(String(row.Values));
await page.getByRole("button", { name: "Search" }).click();
// Handle search results safely
const outcome = await handleSearchResults(page);
console.log(`Search outcome for "${row.Status}":`, outcome);
});
});
});
test.describe("Address search", () => {
test("Address search AddressLine1", async ({ page }) => {
await page.goto("/");
const acceptButton = page.getByRole("button", { name: "Accept cookies" });
if (await acceptButton.isVisible()) await acceptButton.click();
await page.getByRole("link", { name: "Address search" }).click();
await page.locator("#addressline1").click();
await page.locator("#addressline1").fill("street");
await page.getByRole("button", { name: "Search" }).click();
// Handle search results safely
const outcome = await handleSearchResults(page);
console.log(`Search outcome for AddressLine1":`, outcome);
});
test("Address search Town", async ({ page }) => {
await page.goto("/");
const acceptButton = page.getByRole("button", { name: "Accept cookies" });
if (await acceptButton.isVisible()) await acceptButton.click();
await page.getByRole("link", { name: "Address search" }).click();
await page.locator("#town").click();
await page.locator("#town").fill("Cardiff");
await page.getByRole("button", { name: "Search" }).click();
// Handle search results safely
const outcome = await handleSearchResults(page);
console.log(`Search outcome for Town":`, outcome);
});
test("Address search County", async ({ page }) => {
await page.goto("/");
const acceptButton = page.getByRole("button", { name: "Accept cookies" });
if (await acceptButton.isVisible()) await acceptButton.click();
await page.getByRole("link", { name: "Address search" }).click();
await page.locator("#county").click();
await page.locator("#county").fill("Cardiff");
await page.getByRole("button", { name: "Search" }).click();
// Handle search results safely
const outcome = await handleSearchResults(page);
console.log(`Search outcome for County":`, outcome);
});
test("Address search Postcode", async ({ page }) => {
await page.goto("/");
const acceptButton = page.getByRole("button", { name: "Accept cookies" });
if (await acceptButton.isVisible()) await acceptButton.click();
await page.getByRole("link", { name: "Address search" }).click();
await page.locator("#postcode").click();
await page.locator("#postcode").fill("cf24");
await page.getByRole("button", { name: "Search" }).click();
// Handle search results safely
const outcome = await handleSearchResults(page);
console.log(`Search outcome for Postcode":`, outcome);
});
test("Address search Appellant or Applicant", async ({ page }) => {
await page.goto("/");
const acceptButton = page.getByRole("button", { name: "Accept cookies" });
if (await acceptButton.isVisible()) await acceptButton.click();
await page.getByRole("link", { name: "Address search" }).click();
await page.locator("#appellantname").click();
await page.locator("#appellantname").fill("David");
await page.locator("#addressline1").click();
await page.locator("#addressline1").fill("Street");
await page.getByRole("button", { name: "Search" }).click();
// Handle search results safely
const outcome = await handleSearchResults(page);
console.log(`Search outcome for Postcode":`, outcome);
});
});
+71
View File
@@ -0,0 +1,71 @@
import { test, expect } from '@playwright/test';
test('test', async ({ page }) => {
await page.locator('body').click();
await page.goto('http://localhost:3000/auth/error?error=Verification
await page.getByRole('link', { name: 'Home', exact: true }).click();
await page.goto('http://localhost:3000/myportal');
await page.goto('http://localhost:3000/myportal/case/CAS-01085-K4R4X0?q=CAS-01085-K4R4X0&adv=false');
await page.getByRole('link', { name: 'Make representation' }).click();
await page.getByRole('combobox').selectOption('Questionnaire');
await page.getByRole('combobox').selectOption('Written representations');
await page.getByText('No').first().click();
await page.getByText('No').nth(1).click();
await page.getByText('No').nth(2).click();
await page.getByText('Yes').nth(2).click();
await page.getByText('No').nth(3).click();
await page.getByRole('paragraph').filter({ hasText: /^$/ }).click();
await page.locator('.ql-editor').fill('w');
await page.locator('div').filter({ hasText: /^w$/ }).nth(2).fill('wdwdwdwdwdw ');
await page.getByRole('button', { name: 'Continue' }).click();
await page.locator('.ql-editor').first().click();
await page.locator('.ql-editor').first().fill('wwwqwqeq wefqewr qwerq');
await page.getByRole('paragraph').nth(4).click();
await page.locator('.ql-editor.ql-blank').first().fill('qweqwe qwrqrt qwe qweqwqwe');
await page.getByRole('paragraph').filter({ hasText: /^$/ }).click();
await page.locator('.ql-editor.ql-blank').first().fill('qweqwe qwrqrt qwe qweqwqweq');
await page.locator('.ql-editor.ql-blank').fill('w e');
await page.locator('div').filter({ hasText: /^w e$/ }).nth(2).fill('w eqewrqwe q');
await page.getByRole('paragraph').filter({ hasText: /^$/ }).click();
await page.locator('div').filter({ hasText: /^w e$/ }).nth(2).fill('w eqewrqwe qweqwe ');
await page.getByText('No').nth(1).click();
await page.getByText('No').nth(2).click();
await page.getByText('No').nth(3).click();
await page.getByText('No').nth(4).click();
await page.getByText('No').nth(5).click();
await page.locator('div:nth-child(8) > .govuk-form-group > .govuk-fieldset > .govuk-radios > div:nth-child(2) > .govuk-radios__item > .govuk-label').click();
await page.locator('div:nth-child(9) > .govuk-fieldset > .govuk-radios > div:nth-child(2) > .govuk-label').click();
await page.locator('div:nth-child(10) > .govuk-form-group > .govuk-fieldset > .govuk-radios > div:nth-child(2) > .govuk-radios__item > .govuk-label').click();
await page.getByRole('button', { name: 'Continue' }).click();
await page.getByText('No').nth(2).click();
await page.getByText('No').nth(3).click();
await page.getByText('No').nth(5).click();
await page.getByText('No', { exact: true }).nth(3).click();
await page.getByText('No', { exact: true }).nth(4).click();
await page.getByRole('button', { name: 'Continue' }).click();
await page.getByRole('group', { name: '26. A copy of the applicants' }).click();
await page.getByText('No').nth(4).click();
await page.getByText('Yes').nth(1).click();
await page.getByText('No', { exact: true }).nth(2).click();
await page.getByText('Yes').nth(2).click();
await page.getByText('No', { exact: true }).nth(3).click();
await page.getByText('No', { exact: true }).nth(4).click();
await page.getByText('No', { exact: true }).nth(5).click();
await page.locator('div:nth-child(9) > .govuk-form-group > .govuk-fieldset > .govuk-radios > div:nth-child(2) > .govuk-radios__item > .govuk-label').click();
await page.locator('div:nth-child(10) > .govuk-form-group > .govuk-fieldset > .govuk-radios > div:nth-child(2) > .govuk-radios__item > .govuk-label').click();
await page.getByRole('button', { name: 'Continue' }).click();
await page.getByText('Drag and drop your files here').click();
await page.getByRole('button', { name: 'Continue' }).click();
await page.getByRole('textbox', { name: 'Signed' }).click();
await page.getByRole('textbox', { name: 'Signed' }).fill('Bob Bob');
await page.getByRole('textbox', { name: 'Date' }).click();
await page.getByRole('option', { name: 'Choose Tuesday, April 14th,' }).click();
await page.getByRole('button', { name: 'Continue' }).click();
await page.getByText('I wish to download a copy of').click();
await page.getByRole('checkbox', { name: 'I confirm I have read the' }).check();
const downloadPromise = page.waitForEvent('download');
await page.getByRole('button', { name: 'Continue' }).click();
const download = await downloadPromise;
await page.getByRole('link', { name: 'Continue' }).click();
await page.goto('http://localhost:3000/myportal');');
});
+5
View File
@@ -0,0 +1,5 @@
import { test, expect } from '@playwright/test';
test('test', async ({ page }) => {
// Recording...
});
+22
View File
@@ -0,0 +1,22 @@
import { test, expect } from "@playwright/test";
test("test", async ({ page }) => {
// Recording...
await page.goto("http://localhost:3000/auth/error?error=Verification");
await page.getByRole("link", { name: "Home", exact: true }).click();
await page.goto("http://localhost:3000/myportal");
await page.getByRole("heading", { name: "Representations awaiting" }).click();
const containerLink = page
.locator("div", { hasText: "Representations awaiting" })
.locator("a")
.first()
.click();
await page.getByText("CAS-01085-K4R4X0").first().click();
await page.goto(
"http://localhost:3000/myportal/representation?case=CAS-01085-K4R4X0&state=edit&created=2026-04-15-12%3A32%3A23_-_LPA_-_Questionnaire_-_CardiffCouncil",
);
await page.getByRole("button", { name: "Save and exit" }).click();
await page.goto("http://localhost:3000/myportal");
});
+22 -1
View File
@@ -579,6 +579,13 @@
"@pkgr/core@^0.1.0": "@pkgr/core@^0.1.0":
version "0.1.1" version "0.1.1"
"@playwright/test@^1.41.2", "@playwright/test@^1.62.1":
version "1.62.1"
resolved "https://registry.npmjs.org/@playwright/test/-/test-1.62.1.tgz"
integrity sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==
dependencies:
playwright "1.62.1"
"@popperjs/core@^2.0.0", "@popperjs/core@^2.11.8": "@popperjs/core@^2.0.0", "@popperjs/core@^2.11.8":
version "2.11.8" version "2.11.8"
@@ -3017,7 +3024,7 @@ fs.realpath@^1.0.0:
fs@0.0.2: fs@0.0.2:
version "0.0.2" version "0.0.2"
fsevents@~2.3.2, fsevents@2.3.3: fsevents@~2.3.2, fsevents@2.3.2, fsevents@2.3.3:
version "2.3.3" version "2.3.3"
function-bind@^1.1.2: function-bind@^1.1.2:
@@ -4475,6 +4482,20 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz" resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz"
integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==
playwright-core@1.62.1:
version "1.62.1"
resolved "https://registry.npmjs.org/playwright-core/-/playwright-core-1.62.1.tgz"
integrity sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==
playwright@1.62.1:
version "1.62.1"
resolved "https://registry.npmjs.org/playwright/-/playwright-1.62.1.tgz"
integrity sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==
dependencies:
playwright-core "1.62.1"
optionalDependencies:
fsevents "2.3.2"
possible-typed-array-names@^1.0.0: possible-typed-array-names@^1.0.0:
version "1.0.0" version "1.0.0"