mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-08-02 16:02:15 +02:00
Merge pull request #2472 from cisagov/rh/2406-clipboard
Issue #2406: Clipboard Functionality [backup]
This commit is contained in:
commit
bb3cfa0e2a
15 changed files with 231 additions and 69 deletions
9
src/package-lock.json
generated
9
src/package-lock.json
generated
|
@ -9,7 +9,7 @@
|
|||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@uswds/uswds": "^3.8.0",
|
||||
"@uswds/uswds": "^3.8.1",
|
||||
"pa11y-ci": "^3.0.1",
|
||||
"sass": "^1.54.8"
|
||||
},
|
||||
|
@ -187,9 +187,10 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@uswds/uswds": {
|
||||
"version": "3.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@uswds/uswds/-/uswds-3.8.0.tgz",
|
||||
"integrity": "sha512-rMwCXe/u4HGkfskvS1Iuabapi/EXku3ChaIFW7y/dUhc7R1TXQhbbfp8YXEjmXPF0yqJnv9T08WPgS0fQqWZ8w==",
|
||||
"version": "3.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@uswds/uswds/-/uswds-3.8.1.tgz",
|
||||
"integrity": "sha512-bKG/B9mJF1v0yoqth48wQDzST5Xyu3OxxpePIPDyhKWS84oDrCehnu3Z88JhSjdIAJMl8dtjtH8YvdO9kZUpAg==",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"dependencies": {
|
||||
"classlist-polyfill": "1.2.0",
|
||||
"object-assign": "4.1.1",
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@uswds/uswds": "^3.8.0",
|
||||
"@uswds/uswds": "^3.8.1",
|
||||
"pa11y-ci": "^3.0.1",
|
||||
"sass": "^1.54.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@uswds/compile": "^1.0.0-beta.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -207,15 +207,11 @@ function addOrRemoveSessionBoolean(name, add){
|
|||
|
||||
|
||||
})();
|
||||
|
||||
/** An IIFE for pages in DjangoAdmin that use a clipboard button
|
||||
*/
|
||||
(function (){
|
||||
|
||||
function copyInnerTextToClipboard(elem) {
|
||||
let text = elem.innerText
|
||||
navigator.clipboard.writeText(text)
|
||||
}
|
||||
|
||||
function copyToClipboardAndChangeIcon(button) {
|
||||
// Assuming the input is the previous sibling of the button
|
||||
let input = button.previousElementSibling;
|
||||
|
@ -224,7 +220,7 @@ function addOrRemoveSessionBoolean(name, add){
|
|||
if (input) {
|
||||
navigator.clipboard.writeText(input.value).then(function() {
|
||||
// Change the icon to a checkmark on successful copy
|
||||
let buttonIcon = button.querySelector('.usa-button__clipboard use');
|
||||
let buttonIcon = button.querySelector('.copy-to-clipboard use');
|
||||
if (buttonIcon) {
|
||||
let currentHref = buttonIcon.getAttribute('xlink:href');
|
||||
let baseHref = currentHref.split('#')[0];
|
||||
|
@ -233,21 +229,17 @@ function addOrRemoveSessionBoolean(name, add){
|
|||
buttonIcon.setAttribute('xlink:href', baseHref + '#check');
|
||||
|
||||
// Change the button text
|
||||
nearestSpan = button.querySelector("span")
|
||||
let nearestSpan = button.querySelector("span")
|
||||
let original_text = nearestSpan.innerText
|
||||
nearestSpan.innerText = "Copied to clipboard"
|
||||
|
||||
setTimeout(function() {
|
||||
// Change back to the copy icon
|
||||
buttonIcon.setAttribute('xlink:href', currentHref);
|
||||
if (button.classList.contains('usa-button__small-text')) {
|
||||
nearestSpan.innerText = "Copy email";
|
||||
} else {
|
||||
nearestSpan.innerText = "Copy";
|
||||
}
|
||||
nearestSpan.innerText = original_text;
|
||||
}, 2000);
|
||||
|
||||
}
|
||||
|
||||
}).catch(function(error) {
|
||||
console.error('Clipboard copy failed', error);
|
||||
});
|
||||
|
@ -255,7 +247,7 @@ function addOrRemoveSessionBoolean(name, add){
|
|||
}
|
||||
|
||||
function handleClipboardButtons() {
|
||||
clipboardButtons = document.querySelectorAll(".usa-button__clipboard")
|
||||
clipboardButtons = document.querySelectorAll(".copy-to-clipboard")
|
||||
clipboardButtons.forEach((button) => {
|
||||
|
||||
// Handle copying the text to your clipboard,
|
||||
|
@ -278,20 +270,7 @@ function addOrRemoveSessionBoolean(name, add){
|
|||
});
|
||||
}
|
||||
|
||||
function handleClipboardLinks() {
|
||||
let emailButtons = document.querySelectorAll(".usa-button__clipboard-link");
|
||||
if (emailButtons){
|
||||
emailButtons.forEach((button) => {
|
||||
button.addEventListener("click", ()=>{
|
||||
copyInnerTextToClipboard(button);
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleClipboardButtons();
|
||||
handleClipboardLinks();
|
||||
|
||||
})();
|
||||
|
||||
|
||||
|
@ -605,3 +584,169 @@ function initializeWidgetOnList(list, parentId) {
|
|||
}
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
/** An IIFE for copy summary button (appears in DomainRegistry models)
|
||||
*/
|
||||
(function (){
|
||||
const copyButton = document.getElementById('id-copy-to-clipboard-summary');
|
||||
|
||||
if (copyButton) {
|
||||
copyButton.addEventListener('click', function() {
|
||||
/// Generate a rich HTML summary text and copy to clipboard
|
||||
|
||||
//------ Organization Type
|
||||
const organizationTypeElement = document.getElementById('id_organization_type');
|
||||
const organizationType = organizationTypeElement.options[organizationTypeElement.selectedIndex].text;
|
||||
|
||||
//------ Alternative Domains
|
||||
const alternativeDomainsDiv = document.querySelector('.form-row.field-alternative_domains .readonly');
|
||||
const alternativeDomainslinks = alternativeDomainsDiv.querySelectorAll('a');
|
||||
const alternativeDomains = Array.from(alternativeDomainslinks).map(link => link.textContent);
|
||||
|
||||
//------ Existing Websites
|
||||
const existingWebsitesDiv = document.querySelector('.form-row.field-current_websites .readonly');
|
||||
const existingWebsiteslinks = existingWebsitesDiv.querySelectorAll('a');
|
||||
const existingWebsites = Array.from(existingWebsiteslinks).map(link => link.textContent);
|
||||
|
||||
//------ Additional Contacts
|
||||
// 1 - Create a hyperlinks map so we can display contact details and also link to the contact
|
||||
const otherContactsDiv = document.querySelector('.form-row.field-other_contacts .readonly');
|
||||
let otherContactLinks = [];
|
||||
const nameToUrlMap = {};
|
||||
if (otherContactsDiv) {
|
||||
otherContactLinks = otherContactsDiv.querySelectorAll('a');
|
||||
otherContactLinks.forEach(link => {
|
||||
const name = link.textContent.trim();
|
||||
const url = link.href;
|
||||
nameToUrlMap[name] = url;
|
||||
});
|
||||
}
|
||||
|
||||
// 2 - Iterate through contact details and assemble html for summary
|
||||
let otherContactsSummary = ""
|
||||
const bulletList = document.createElement('ul');
|
||||
|
||||
// CASE 1 - Contacts are not in a table (this happens if there is only one or two other contacts)
|
||||
const contacts = document.querySelectorAll('.field-other_contacts .dja-detail-list dd');
|
||||
if (contacts) {
|
||||
contacts.forEach(contact => {
|
||||
// Check if the <dl> element is not empty
|
||||
const name = contact.querySelector('a#contact_info_name')?.innerText;
|
||||
const title = contact.querySelector('span#contact_info_title')?.innerText;
|
||||
const email = contact.querySelector('span#contact_info_email')?.innerText;
|
||||
const phone = contact.querySelector('span#contact_info_phone')?.innerText;
|
||||
const url = nameToUrlMap[name] || '#';
|
||||
// Format the contact information
|
||||
const listItem = document.createElement('li');
|
||||
listItem.innerHTML = `<a href="${url}">${name}</a>, ${title}, ${email}, ${phone}`;
|
||||
bulletList.appendChild(listItem);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// CASE 2 - Contacts are in a table (this happens if there is more than 2 contacts)
|
||||
const otherContactsTable = document.querySelector('.form-row.field-other_contacts table tbody');
|
||||
if (otherContactsTable) {
|
||||
const otherContactsRows = otherContactsTable.querySelectorAll('tr');
|
||||
otherContactsRows.forEach(contactRow => {
|
||||
// Extract the contact details
|
||||
const name = contactRow.querySelector('th').textContent.trim();
|
||||
const title = contactRow.querySelectorAll('td')[0].textContent.trim();
|
||||
const email = contactRow.querySelectorAll('td')[1].textContent.trim();
|
||||
const phone = contactRow.querySelectorAll('td')[2].textContent.trim();
|
||||
const url = nameToUrlMap[name] || '#';
|
||||
// Format the contact information
|
||||
const listItem = document.createElement('li');
|
||||
listItem.innerHTML = `<a href="${url}">${name}</a>, ${title}, ${email}, ${phone}`;
|
||||
bulletList.appendChild(listItem);
|
||||
});
|
||||
}
|
||||
otherContactsSummary += bulletList.outerHTML
|
||||
|
||||
|
||||
//------ Requested Domains
|
||||
const requestedDomainElement = document.getElementById('id_requested_domain');
|
||||
const requestedDomain = requestedDomainElement.options[requestedDomainElement.selectedIndex].text;
|
||||
|
||||
//------ Submitter
|
||||
// Function to extract text by ID and handle missing elements
|
||||
function extractTextById(id, divElement) {
|
||||
if (divElement) {
|
||||
const element = divElement.querySelector(`#${id}`);
|
||||
return element ? ", " + element.textContent.trim() : '';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
// Extract the submitter name, title, email, and phone number
|
||||
const submitterDiv = document.querySelector('.form-row.field-submitter');
|
||||
const submitterNameElement = document.getElementById('id_submitter');
|
||||
const submitterName = submitterNameElement.options[submitterNameElement.selectedIndex].text;
|
||||
const submitterTitle = extractTextById('contact_info_title', submitterDiv);
|
||||
const submitterEmail = extractTextById('contact_info_email', submitterDiv);
|
||||
const submitterPhone = extractTextById('contact_info_phone', submitterDiv);
|
||||
let submitterInfo = `${submitterName}${submitterTitle}${submitterEmail}${submitterPhone}`;
|
||||
|
||||
|
||||
//------ Senior Official
|
||||
const seniorOfficialDiv = document.querySelector('.form-row.field-senior_official');
|
||||
const seniorOfficialElement = document.getElementById('id_senior_official');
|
||||
const seniorOfficialName = seniorOfficialElement.options[seniorOfficialElement.selectedIndex].text;
|
||||
const seniorOfficialTitle = extractTextById('contact_info_title', seniorOfficialDiv);
|
||||
const seniorOfficialEmail = extractTextById('contact_info_email', seniorOfficialDiv);
|
||||
const seniorOfficialPhone = extractTextById('contact_info_phone', seniorOfficialDiv);
|
||||
let seniorOfficialInfo = `${seniorOfficialName}${seniorOfficialTitle}${seniorOfficialEmail}${seniorOfficialPhone}`;
|
||||
|
||||
const html_summary = `<strong>Recommendation:</strong></br>` +
|
||||
`<strong>Organization Type:</strong> ${organizationType}</br>` +
|
||||
`<strong>Requested Domain:</strong> ${requestedDomain}</br>` +
|
||||
`<strong>Current Websites:</strong> ${existingWebsites.join(', ')}</br>` +
|
||||
`<strong>Rationale:</strong></br>` +
|
||||
`<strong>Alternative Domains:</strong> ${alternativeDomains.join(', ')}</br>` +
|
||||
`<strong>Submitter:</strong> ${submitterInfo}</br>` +
|
||||
`<strong>Senior Official:</strong> ${seniorOfficialInfo}</br>` +
|
||||
`<strong>Other Employees:</strong> ${otherContactsSummary}</br>`;
|
||||
|
||||
//Replace </br> with \n, then strip out all remaining html tags (replace <...> with '')
|
||||
const plain_summary = html_summary.replace(/<\/br>|<br>/g, '\n').replace(/<\/?[^>]+(>|$)/g, '');
|
||||
|
||||
// Create Blobs with the summary content
|
||||
const html_blob = new Blob([html_summary], { type: 'text/html' });
|
||||
const plain_blob = new Blob([plain_summary], { type: 'text/plain' });
|
||||
|
||||
// Create a ClipboardItem with the Blobs
|
||||
const clipboardItem = new ClipboardItem({
|
||||
'text/html': html_blob,
|
||||
'text/plain': plain_blob
|
||||
});
|
||||
|
||||
// Write the ClipboardItem to the clipboard
|
||||
navigator.clipboard.write([clipboardItem]).then(() => {
|
||||
// Change the icon to a checkmark on successful copy
|
||||
let buttonIcon = copyButton.querySelector('use');
|
||||
if (buttonIcon) {
|
||||
let currentHref = buttonIcon.getAttribute('xlink:href');
|
||||
let baseHref = currentHref.split('#')[0];
|
||||
|
||||
// Append the new icon reference
|
||||
buttonIcon.setAttribute('xlink:href', baseHref + '#check');
|
||||
|
||||
// Change the button text
|
||||
nearestSpan = copyButton.querySelector("span")
|
||||
original_text = nearestSpan.innerText
|
||||
nearestSpan.innerText = "Copied to clipboard"
|
||||
|
||||
setTimeout(function() {
|
||||
// Change back to the copy icon
|
||||
buttonIcon.setAttribute('xlink:href', currentHref);
|
||||
nearestSpan.innerText = original_text
|
||||
}, 2000);
|
||||
|
||||
}
|
||||
console.log('Summary copied to clipboard successfully!');
|
||||
}).catch(err => {
|
||||
console.error('Failed to copy text: ', err);
|
||||
});
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
|
|
@ -369,9 +369,6 @@ input.admin-confirm-button {
|
|||
padding: 10px 8px;
|
||||
line-height: normal;
|
||||
}
|
||||
.usa-icon {
|
||||
top: 2px;
|
||||
}
|
||||
a.button:active, a.button:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
@ -447,15 +444,12 @@ address.margin-top-neg-1__detail-list {
|
|||
}
|
||||
}
|
||||
|
||||
td button.usa-button__clipboard-link, address.dja-address-contact-list {
|
||||
address.dja-address-contact-list {
|
||||
font-size: unset;
|
||||
}
|
||||
|
||||
address.dja-address-contact-list {
|
||||
color: var(--body-quiet-color);
|
||||
button.usa-button__clipboard-link {
|
||||
font-size: unset;
|
||||
}
|
||||
}
|
||||
|
||||
// Mimic the normal label size
|
||||
|
@ -464,11 +458,18 @@ address.dja-address-contact-list {
|
|||
font-size: 0.875rem;
|
||||
color: var(--body-quiet-color);
|
||||
}
|
||||
}
|
||||
|
||||
address button.usa-button__clipboard-link, td button.usa-button__clipboard-link {
|
||||
font-size: 0.875rem !important;
|
||||
}
|
||||
// Targets the unstyled buttons in the form
|
||||
.button--clipboard {
|
||||
color: var(--link-fg);
|
||||
}
|
||||
|
||||
// Targets the DJA buttom with a nested icon
|
||||
button .usa-icon,
|
||||
.button .usa-icon,
|
||||
.button--clipboard .usa-icon {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.errors span.select2-selection {
|
||||
|
@ -663,7 +664,7 @@ address.dja-address-contact-list {
|
|||
align-items: center;
|
||||
|
||||
|
||||
.usa-button__icon {
|
||||
.usa-button--icon {
|
||||
position: absolute;
|
||||
right: auto;
|
||||
left: 4px;
|
||||
|
@ -681,10 +682,6 @@ address.dja-address-contact-list {
|
|||
}
|
||||
}
|
||||
|
||||
button.usa-button__clipboard {
|
||||
color: var(--link-fg);
|
||||
}
|
||||
|
||||
.no-outline-on-click:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
|
|
|
@ -213,4 +213,4 @@ a.usa-button--unstyled:visited {
|
|||
|
||||
.margin-right-neg-4px {
|
||||
margin-right: -4px;
|
||||
}
|
||||
}
|
|
@ -15,3 +15,4 @@
|
|||
margin-right: units(0.5);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,4 +27,4 @@
|
|||
|
||||
/*--------------------------------------------------
|
||||
--- Admin ---------------------------------*/
|
||||
@forward "admin";
|
||||
@forward "admin";
|
|
@ -1,4 +1,5 @@
|
|||
{% extends "admin/change_form.html" %}
|
||||
{% load static i18n %} <!-- Add this line to load static template tag -->
|
||||
|
||||
{% comment %} Replace the Django ul markup with a div. We'll edit the child markup accordingly in change_form_object_tools {% endcomment %}
|
||||
{% block object-tools %}
|
||||
|
@ -9,4 +10,4 @@
|
|||
{% endblock %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
|
@ -1,4 +1,5 @@
|
|||
{% load i18n admin_urls %}
|
||||
{% load i18n static %}
|
||||
|
||||
{% comment %} Replace li with p for more semantic HTML if we have a single child {% endcomment %}
|
||||
{% block object-tools-items %}
|
||||
|
@ -13,8 +14,21 @@
|
|||
</li>
|
||||
</ul>
|
||||
{% else %}
|
||||
<p class="margin-0 padding-0">
|
||||
<a href="{% add_preserved_filters history_url %}" class="historylink">{% translate "History" %}</a>
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="{% add_preserved_filters history_url %}">{% translate "History" %}</a>
|
||||
</li>
|
||||
{% if opts.model_name == 'domainrequest' %}
|
||||
<li>
|
||||
<a id="id-copy-to-clipboard-summary" class="button--clipboard" type="button" href="#">
|
||||
<svg class="usa-icon" >
|
||||
<use xlink:href="{%static 'img/sprite.svg'%}#content_copy"></use>
|
||||
</svg>
|
||||
<span>{% translate "Copy request summary" %}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ Template for an input field with a clipboard
|
|||
<div class="admin-icon-group">
|
||||
{{ field }}
|
||||
<button
|
||||
class="usa-button usa-button--unstyled padding-left-1 usa-button__icon usa-button__clipboard"
|
||||
class="usa-button usa-button--unstyled padding-left-1 usa-button--icon button--clipboard copy-to-clipboard"
|
||||
type="button"
|
||||
>
|
||||
<div class="no-outline-on-click">
|
||||
|
@ -25,7 +25,7 @@ Template for an input field with a clipboard
|
|||
<div class="admin-icon-group admin-icon-group__clipboard-link">
|
||||
<input aria-hidden="true" class="display-none" value="{{ field.email }}" />
|
||||
<button
|
||||
class="usa-button usa-button--unstyled padding-right-1 usa-button__icon usa-button__clipboard text-no-underline"
|
||||
class="usa-button usa-button--unstyled padding-right-1 usa-button--icon button--clipboard copy-to-clipboard text-no-underline"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
|
|
|
@ -2,25 +2,28 @@
|
|||
|
||||
<address class="{% if no_title_top_padding %}margin-top-neg-1__detail-list{% endif %} {% if user.has_contact_info %}margin-bottom-1{% endif %} dja-address-contact-list">
|
||||
|
||||
|
||||
{% if show_formatted_name %}
|
||||
{% if user.get_formatted_name %}
|
||||
<a href="{% url 'admin:registrar_contact_change' user.id %}">{{ user.get_formatted_name }}</a><br />
|
||||
<a id="contact_info_name" href="{% url 'admin:registrar_contact_change' user.id %}">{{ user.get_formatted_name }}</a>
|
||||
{% else %}
|
||||
None<br />
|
||||
None
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</br>
|
||||
|
||||
{% if user.has_contact_info %}
|
||||
{# Title #}
|
||||
{% if user.title %}
|
||||
{{ user.title }}
|
||||
<br>
|
||||
<span id="contact_info_title">{{ user.title }}</span>
|
||||
{% else %}
|
||||
None<br>
|
||||
None
|
||||
{% endif %}
|
||||
</br>
|
||||
|
||||
{# Email #}
|
||||
{% if user.email %}
|
||||
{{ user.email }}
|
||||
<span id="contact_info_email">{{ user.email }}</span>
|
||||
{% include "admin/input_with_clipboard.html" with field=user invisible_input_field=True %}
|
||||
<br class="admin-icon-group__br">
|
||||
{% else %}
|
||||
|
@ -29,7 +32,7 @@
|
|||
|
||||
{# Phone #}
|
||||
{% if user.phone %}
|
||||
{{ user.phone }}
|
||||
<span id="contact_info_phone">{{ user.phone }}</span>
|
||||
<br>
|
||||
{% else %}
|
||||
None<br>
|
||||
|
@ -40,6 +43,6 @@
|
|||
{% endif %}
|
||||
|
||||
{% if user_verification_type %}
|
||||
{{ user_verification_type }}
|
||||
<span id="contact_info_phone">{{ user_verification_type }}</span>
|
||||
{% endif %}
|
||||
</address>
|
||||
|
|
|
@ -219,7 +219,7 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html)
|
|||
<td class="padding-left-1 text-size-small">
|
||||
<input aria-hidden="true" class="display-none" value="{{ contact.email }}" />
|
||||
<button
|
||||
class="usa-button usa-button--unstyled padding-right-1 usa-button__icon usa-button__clipboard usa-button__small-text text-no-underline"
|
||||
class="usa-button usa-button--unstyled padding-right-1 usa-button--icon button--clipboard copy-to-clipboard usa-button__small-text text-no-underline"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
|
|
|
@ -584,7 +584,7 @@ class TestDomainInformationAdmin(TestCase):
|
|||
self.test_helper.assert_response_contains_distinct_values(response, expected_other_employees_fields)
|
||||
|
||||
# Test for the copy link
|
||||
self.assertContains(response, "usa-button__clipboard", count=4)
|
||||
self.assertContains(response, "button--clipboard", count=4)
|
||||
|
||||
# cleanup this test
|
||||
domain_info.delete()
|
||||
|
|
|
@ -444,7 +444,7 @@ class TestDomainAdminWithClient(TestCase):
|
|||
self.assertContains(response, "(555) 555 5557")
|
||||
|
||||
# Test for the copy link
|
||||
self.assertContains(response, "usa-button__clipboard")
|
||||
self.assertContains(response, "button--clipboard")
|
||||
|
||||
# cleanup from this test
|
||||
domain.delete()
|
||||
|
|
|
@ -1411,7 +1411,7 @@ class TestDomainRequestAdmin(MockEppLib):
|
|||
self.test_helper.assert_response_contains_distinct_values(response, expected_other_employees_fields)
|
||||
|
||||
# Test for the copy link
|
||||
self.assertContains(response, "usa-button__clipboard", count=4)
|
||||
self.assertContains(response, "button--clipboard", count=5)
|
||||
|
||||
# Test that Creator counts display properly
|
||||
self.assertNotContains(response, "Approved domains")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue