Skip to content

Commit bb5fd18

Browse files
authored
Genericize OIDC templates, forms and views (#15143)
* Automatically switch to tab with errors if present * Forms don't need to be properties * Refactor common parts out of forms and views * Refactor templates to handle multiple providers * Update translations * Add tests for the Horizontal Tabs controller
1 parent 5147ff2 commit bb5fd18

File tree

13 files changed

+452
-266
lines changed

13 files changed

+452
-266
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/* Licensed under the Apache License, Version 2.0 (the "License");
2+
* you may not use this file except in compliance with the License.
3+
* You may obtain a copy of the License at
4+
*
5+
* http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
14+
/* global expect, beforeEach, describe, it */
15+
16+
import { Application } from "@hotwired/stimulus";
17+
import HorizontalTabsController from "../../warehouse/static/js/warehouse/controllers/horizontal_tabs_controller";
18+
19+
const tabsHTML = `
20+
<div class="horizontal-tabs" data-controller="horizontal-tabs" data-horizontal-tabs-index="0">
21+
<div class="horizontal-tabs__tabbar">
22+
<button data-horizontal-tabs-target="tab" data-action="horizontal-tabs#change" class="tab is-active">
23+
Publisher 1
24+
</button>
25+
<button data-horizontal-tabs-target="tab" data-action="horizontal-tabs#change" class="tab">
26+
Publisher 2
27+
</button>
28+
<button data-horizontal-tabs-target="tab" data-action="horizontal-tabs#change" class="tab">
29+
Publisher 3
30+
</button>
31+
</div>
32+
<div class="horizontal-tabs__tabcontent is-hidden" data-horizontal-tabs-target="tabPanel">
33+
<div>Publisher Form 1</div>
34+
</div>
35+
<div class="horizontal-tabs__tabcontent" data-horizontal-tabs-target="tabPanel">
36+
<div>Publisher Form 2</div>
37+
</div>
38+
<div class="horizontal-tabs__tabcontent" data-horizontal-tabs-target="tabPanel">
39+
<div>Publisher Form 3</div>
40+
</div>
41+
</div>
42+
`;
43+
44+
describe("Horizontal tabs controller", () => {
45+
beforeEach(() => {
46+
document.body.innerHTML = tabsHTML;
47+
const application = Application.start();
48+
application.register("horizontal-tabs", HorizontalTabsController);
49+
});
50+
51+
describe("on initializtion", () => {
52+
it("the first tab is shown", () => {
53+
const tabs = document.querySelectorAll(".tab");
54+
const content = document.querySelectorAll(".horizontal-tabs__tabcontent");
55+
56+
// First tab is shown
57+
expect(tabs[0]).toHaveClass("is-active");
58+
expect(content[0]).not.toHaveClass("is-hidden");
59+
60+
// The other tabs are not shown
61+
expect(tabs[1]).not.toHaveClass("is-active");
62+
expect(content[1]).toHaveClass("is-hidden");
63+
expect(tabs[2]).not.toHaveClass("is-active");
64+
expect(content[2]).toHaveClass("is-hidden");
65+
});
66+
});
67+
68+
describe("on change", () => {
69+
it("updates the active tab and panel when a tab is clicked", () => {
70+
const tabs = document.querySelectorAll(".tab");
71+
const content = document.querySelectorAll(".horizontal-tabs__tabcontent");
72+
73+
// Click the second tab
74+
tabs[1].click();
75+
76+
// First tab is not shown
77+
expect(tabs[0]).not.toHaveClass("is-active");
78+
expect(content[0]).toHaveClass("is-hidden");
79+
80+
// Second tab is shown
81+
expect(tabs[1]).toHaveClass("is-active");
82+
expect(content[1]).not.toHaveClass("is-hidden");
83+
84+
// Third tab is not shown
85+
expect(tabs[2]).not.toHaveClass("is-active");
86+
expect(content[2]).toHaveClass("is-hidden");
87+
});
88+
});
89+
90+
describe("on initializtion with errors", () => {
91+
beforeEach(() => {
92+
// Add some errors to the second tab
93+
const secondTabPanel = document.querySelectorAll(".horizontal-tabs__tabcontent")[1];
94+
secondTabPanel.innerHTML = "<div id='errors'></div>" + secondTabPanel.innerHTML;
95+
const application = Application.start();
96+
application.register("horizontal-tabs", HorizontalTabsController);
97+
});
98+
it("the tab with errors is shown", () => {
99+
const tabs = document.querySelectorAll(".tab");
100+
const content = document.querySelectorAll(".horizontal-tabs__tabcontent");
101+
102+
// First tab is not shown
103+
expect(tabs[0]).not.toHaveClass("is-active");
104+
expect(content[0]).toHaveClass("is-hidden");
105+
106+
// Second tab is shown
107+
expect(tabs[1]).toHaveClass("is-active");
108+
expect(content[1]).not.toHaveClass("is-hidden");
109+
110+
// Third tab is not shown
111+
expect(tabs[2]).not.toHaveClass("is-active");
112+
expect(content[2]).toHaveClass("is-hidden");
113+
});
114+
});
115+
});

tests/unit/accounts/test_views.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3232,6 +3232,12 @@ class TestManageAccountPublishingViews:
32323232
def test_initializes(self, metrics):
32333233
request = pretend.stub(
32343234
find_service=pretend.call_recorder(lambda *a, **kw: metrics),
3235+
POST=MultiDict(),
3236+
registry=pretend.stub(
3237+
settings={
3238+
"github.token": "fake-api-token",
3239+
}
3240+
),
32353241
)
32363242
view = views.ManageAccountPublishingViews(request)
32373243

@@ -3275,6 +3281,12 @@ def find_service(iface, name=None, context=None):
32753281
find_service=pretend.call_recorder(find_service),
32763282
user=pretend.stub(id=pretend.stub()),
32773283
remote_addr=pretend.stub(),
3284+
POST=MultiDict(),
3285+
registry=pretend.stub(
3286+
settings={
3287+
"github.token": "fake-api-token",
3288+
}
3289+
),
32783290
)
32793291

32803292
view = views.ManageAccountPublishingViews(request)
@@ -3549,10 +3561,6 @@ def test_add_pending_github_oidc_publisher_too_many_already(
35493561
"project_name": "some-other-project-name",
35503562
}
35513563
)
3552-
default_response = pretend.stub()
3553-
monkeypatch.setattr(
3554-
views.ManageAccountPublishingViews, "default_response", default_response
3555-
)
35563564

35573565
view = views.ManageAccountPublishingViews(db_request)
35583566

tests/unit/manage/test_views.py

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5733,6 +5733,12 @@ def test_initializes(self, metrics):
57335733
project = pretend.stub()
57345734
request = pretend.stub(
57355735
find_service=pretend.call_recorder(lambda *a, **kw: metrics),
5736+
registry=pretend.stub(
5737+
settings={
5738+
"github.token": "fake-api-token",
5739+
},
5740+
),
5741+
POST=MultiDict(),
57365742
)
57375743
view = views.ManageOIDCPublisherViews(project, request)
57385744

@@ -5778,6 +5784,12 @@ def find_service(iface, name=None, context=None):
57785784
find_service=pretend.call_recorder(find_service),
57795785
user=pretend.stub(id=pretend.stub()),
57805786
remote_addr=pretend.stub(),
5787+
registry=pretend.stub(
5788+
settings={
5789+
"github.token": "fake-api-token",
5790+
},
5791+
),
5792+
POST=MultiDict(),
57815793
)
57825794

57835795
view = views.ManageOIDCPublisherViews(project, request)
@@ -5818,25 +5830,16 @@ def test_manage_project_oidc_publishers(self, monkeypatch):
58185830
flags=pretend.stub(
58195831
disallow_oidc=pretend.call_recorder(lambda f=None: False)
58205832
),
5821-
POST=pretend.stub(),
5822-
)
5823-
5824-
github_publisher_form_obj = pretend.stub()
5825-
github_publisher_form_cls = pretend.call_recorder(
5826-
lambda *a, **kw: github_publisher_form_obj
5833+
POST=MultiDict(),
58275834
)
5828-
monkeypatch.setattr(views, "GitHubPublisherForm", github_publisher_form_cls)
58295835

58305836
view = views.ManageOIDCPublisherViews(project, request)
58315837
assert view.manage_project_oidc_publishers() == {
58325838
"project": project,
5833-
"github_publisher_form": github_publisher_form_obj,
5839+
"github_publisher_form": view.github_publisher_form,
58345840
}
58355841

58365842
assert request.flags.disallow_oidc.calls == [pretend.call()]
5837-
assert github_publisher_form_cls.calls == [
5838-
pretend.call(request.POST, api_token="fake-api-token")
5839-
]
58405843

58415844
def test_manage_project_oidc_publishers_admin_disabled(
58425845
self, monkeypatch, pyramid_request
@@ -5855,19 +5858,13 @@ def test_manage_project_oidc_publishers_admin_disabled(
58555858
pyramid_request.session = pretend.stub(
58565859
flash=pretend.call_recorder(lambda *a, **kw: None)
58575860
)
5858-
pyramid_request.POST = pretend.stub()
5861+
pyramid_request.POST = MultiDict()
58595862

58605863
view = views.ManageOIDCPublisherViews(project, pyramid_request)
5861-
github_publisher_form_obj = pretend.stub()
5862-
github_publisher_form_cls = pretend.call_recorder(
5863-
lambda *a, **kw: github_publisher_form_obj
5864-
)
5865-
monkeypatch.setattr(views, "GitHubPublisherForm", github_publisher_form_cls)
58665864

5867-
view = views.ManageOIDCPublisherViews(project, pyramid_request)
58685865
assert view.manage_project_oidc_publishers() == {
58695866
"project": project,
5870-
"github_publisher_form": github_publisher_form_obj,
5867+
"github_publisher_form": view.github_publisher_form,
58715868
}
58725869

58735870
assert pyramid_request.flags.disallow_oidc.calls == [pretend.call()]
@@ -5880,9 +5877,6 @@ def test_manage_project_oidc_publishers_admin_disabled(
58805877
queue="error",
58815878
)
58825879
]
5883-
assert github_publisher_form_cls.calls == [
5884-
pretend.call(pyramid_request.POST, api_token="fake-api-token")
5885-
]
58865880

58875881
def test_add_github_oidc_publisher_preexisting(self, metrics, monkeypatch):
58885882
publisher = pretend.stub(
@@ -6130,11 +6124,6 @@ def test_add_github_oidc_publisher_already_registered_with_project(
61306124
)
61316125

61326126
view = views.ManageOIDCPublisherViews(project, db_request)
6133-
monkeypatch.setattr(
6134-
views.ManageOIDCPublisherViews,
6135-
"github_publisher_form",
6136-
view.github_publisher_form,
6137-
)
61386127
monkeypatch.setattr(
61396128
views.GitHubPublisherForm,
61406129
"_lookup_owner",
@@ -6175,6 +6164,7 @@ def test_add_github_oidc_publisher_ratelimited(self, metrics, monkeypatch):
61756164
disallow_oidc=pretend.call_recorder(lambda f=None: False)
61766165
),
61776166
_=lambda s: s,
6167+
POST=MultiDict(),
61786168
)
61796169

61806170
view = views.ManageOIDCPublisherViews(project, request)
@@ -6210,6 +6200,8 @@ def test_add_github_oidc_publisher_admin_disabled(self, monkeypatch):
62106200
),
62116201
session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)),
62126202
_=lambda s: s,
6203+
POST=MultiDict(),
6204+
registry=pretend.stub(settings={}),
62136205
)
62146206

62156207
view = views.ManageOIDCPublisherViews(project, request)
@@ -6239,6 +6231,8 @@ def test_add_github_oidc_publisher_invalid_form(self, metrics, monkeypatch):
62396231
),
62406232
session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)),
62416233
_=lambda s: s,
6234+
POST=MultiDict(),
6235+
registry=pretend.stub(settings={}),
62426236
)
62436237

62446238
github_publisher_form_obj = pretend.stub(
@@ -6459,7 +6453,8 @@ def test_delete_oidc_publisher_invalid_form(self, metrics, monkeypatch):
64596453
flags=pretend.stub(
64606454
disallow_oidc=pretend.call_recorder(lambda f=None: False)
64616455
),
6462-
POST=pretend.stub(),
6456+
POST=MultiDict(),
6457+
registry=pretend.stub(settings={}),
64636458
)
64646459

64656460
delete_publisher_form_obj = pretend.stub(
@@ -6513,7 +6508,8 @@ def test_delete_oidc_publisher_not_found(
65136508
disallow_oidc=pretend.call_recorder(lambda f=None: False)
65146509
),
65156510
session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)),
6516-
POST=pretend.stub(),
6511+
POST=MultiDict(),
6512+
registry=pretend.stub(settings={}),
65176513
db=pretend.stub(
65186514
get=pretend.call_recorder(lambda *a, **kw: other_publisher),
65196515
),
@@ -6562,6 +6558,8 @@ def test_delete_oidc_publisher_admin_disabled(self, monkeypatch):
65626558
disallow_oidc=pretend.call_recorder(lambda f=None: True)
65636559
),
65646560
session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)),
6561+
POST=MultiDict(),
6562+
registry=pretend.stub(settings={}),
65656563
)
65666564

65676565
view = views.ManageOIDCPublisherViews(project, request)

0 commit comments

Comments
 (0)