Skip to content

Commit 455cbf4

Browse files
solimantreidbarbersnowystinger
authored
feat: Support fragments in collections (#6430)
Co-authored-by: Reid Barber <[email protected]> Co-authored-by: Robert Snow <[email protected]>
1 parent 4969019 commit 455cbf4

File tree

2 files changed

+408
-2
lines changed

2 files changed

+408
-2
lines changed

packages/@react-spectrum/tabs/test/Tabs.test.js

Lines changed: 382 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,4 +890,386 @@ describe('Tabs', function () {
890890
fireEvent.keyDown(tabs[1], {key: 'ArrowRight'});
891891
expect(tabs[2]).toHaveAttribute('aria-selected', 'true');
892892
});
893+
894+
describe('when using fragments', function () {
895+
it('renders fragment with children properly', function () {
896+
let container = render(
897+
<Provider theme={theme}>
898+
<Tabs aria-label="Tab Example" maxWidth={500}>
899+
<TabList>
900+
<>
901+
<Item>Tab 1</Item>
902+
<Item>Tab 2</Item>
903+
</>
904+
</TabList>
905+
<TabPanels>
906+
<>
907+
<Item>
908+
Tab 1 content
909+
</Item>
910+
<Item>
911+
Tab 2 content
912+
</Item>
913+
</>
914+
</TabPanels>
915+
</Tabs>
916+
</Provider>
917+
);
918+
919+
let tablist = container.getByRole('tablist');
920+
expect(tablist).toBeTruthy();
921+
922+
expect(tablist).toHaveAttribute('aria-orientation', 'horizontal');
923+
924+
let tabs = within(tablist).getAllByRole('tab');
925+
expect(tabs.length).toBe(2);
926+
927+
for (let tab of tabs) {
928+
expect(tab).toHaveAttribute('tabindex');
929+
expect(tab).toHaveAttribute('aria-selected');
930+
let isSelected = tab.getAttribute('aria-selected') === 'true';
931+
if (isSelected) {
932+
expect(tab).toHaveAttribute('aria-controls');
933+
let tabpanel = document.getElementById(tab.getAttribute('aria-controls'));
934+
expect(tabpanel).toBeTruthy();
935+
expect(tabpanel).toHaveAttribute('aria-labelledby', tab.id);
936+
expect(tabpanel).toHaveAttribute('role', 'tabpanel');
937+
expect(tabpanel).toHaveTextContent('Tab 1 content');
938+
}
939+
}
940+
});
941+
942+
it('renders beginning fragment sibling properly', function () {
943+
let container = render(
944+
<Provider theme={theme}>
945+
<Tabs aria-label="Tab Example" maxWidth={500}>
946+
<TabList>
947+
<>
948+
<Item>Tab 1</Item>
949+
</>
950+
<Item>Tab 2</Item>
951+
</TabList>
952+
<TabPanels>
953+
<>
954+
<Item>
955+
Tab 1 content
956+
</Item>
957+
</>
958+
<Item>
959+
Tab 2 content
960+
</Item>
961+
</TabPanels>
962+
</Tabs>
963+
</Provider>
964+
);
965+
966+
let tablist = container.getByRole('tablist');
967+
expect(tablist).toBeTruthy();
968+
969+
expect(tablist).toHaveAttribute('aria-orientation', 'horizontal');
970+
971+
let tabs = within(tablist).getAllByRole('tab');
972+
expect(tabs.length).toBe(2);
973+
974+
for (let tab of tabs) {
975+
expect(tab).toHaveAttribute('tabindex');
976+
expect(tab).toHaveAttribute('aria-selected');
977+
let isSelected = tab.getAttribute('aria-selected') === 'true';
978+
if (isSelected) {
979+
expect(tab).toHaveAttribute('aria-controls');
980+
let tabpanel = document.getElementById(tab.getAttribute('aria-controls'));
981+
expect(tabpanel).toBeTruthy();
982+
expect(tabpanel).toHaveAttribute('aria-labelledby', tab.id);
983+
expect(tabpanel).toHaveAttribute('role', 'tabpanel');
984+
expect(tabpanel).toHaveTextContent('Tab 1 content');
985+
}
986+
}
987+
});
988+
989+
it('renders middle fragment sibling properly', function () {
990+
let container = render(
991+
<Provider theme={theme}>
992+
<Tabs aria-label="Tab Example" maxWidth={500}>
993+
<TabList>
994+
<Item>Tab 1</Item>
995+
<>
996+
<Item>Tab 2</Item>
997+
</>
998+
<Item>Tab 3</Item>
999+
</TabList>
1000+
<TabPanels>
1001+
<Item>
1002+
Tab 1 content
1003+
</Item>
1004+
<>
1005+
<Item>
1006+
Tab 2 content
1007+
</Item>
1008+
</>
1009+
<Item>
1010+
Tab 3 content
1011+
</Item>
1012+
</TabPanels>
1013+
</Tabs>
1014+
</Provider>
1015+
);
1016+
1017+
let tablist = container.getByRole('tablist');
1018+
expect(tablist).toBeTruthy();
1019+
1020+
expect(tablist).toHaveAttribute('aria-orientation', 'horizontal');
1021+
1022+
let tabs = within(tablist).getAllByRole('tab');
1023+
expect(tabs.length).toBe(3);
1024+
1025+
for (let tab of tabs) {
1026+
expect(tab).toHaveAttribute('tabindex');
1027+
expect(tab).toHaveAttribute('aria-selected');
1028+
let isSelected = tab.getAttribute('aria-selected') === 'true';
1029+
if (isSelected) {
1030+
expect(tab).toHaveAttribute('aria-controls');
1031+
let tabpanel = document.getElementById(tab.getAttribute('aria-controls'));
1032+
expect(tabpanel).toBeTruthy();
1033+
expect(tabpanel).toHaveAttribute('aria-labelledby', tab.id);
1034+
expect(tabpanel).toHaveAttribute('role', 'tabpanel');
1035+
expect(tabpanel).toHaveTextContent('Tab 1 content');
1036+
}
1037+
}
1038+
});
1039+
1040+
it('renders ending fragment sibling properly', function () {
1041+
let container = render(
1042+
<Provider theme={theme}>
1043+
<Tabs aria-label="Tab Example" maxWidth={500}>
1044+
<TabList>
1045+
<Item>Tab 1</Item>
1046+
<>
1047+
<Item>Tab 2</Item>
1048+
</>
1049+
</TabList>
1050+
<TabPanels>
1051+
<Item>
1052+
Tab 1 content
1053+
</Item>
1054+
<>
1055+
<Item>
1056+
Tab 2 content
1057+
</Item>
1058+
</>
1059+
</TabPanels>
1060+
</Tabs>
1061+
</Provider>
1062+
);
1063+
1064+
let tablist = container.getByRole('tablist');
1065+
expect(tablist).toBeTruthy();
1066+
1067+
expect(tablist).toHaveAttribute('aria-orientation', 'horizontal');
1068+
1069+
let tabs = within(tablist).getAllByRole('tab');
1070+
expect(tabs.length).toBe(2);
1071+
1072+
for (let tab of tabs) {
1073+
expect(tab).toHaveAttribute('tabindex');
1074+
expect(tab).toHaveAttribute('aria-selected');
1075+
let isSelected = tab.getAttribute('aria-selected') === 'true';
1076+
if (isSelected) {
1077+
expect(tab).toHaveAttribute('aria-controls');
1078+
let tabpanel = document.getElementById(tab.getAttribute('aria-controls'));
1079+
expect(tabpanel).toBeTruthy();
1080+
expect(tabpanel).toHaveAttribute('aria-labelledby', tab.id);
1081+
expect(tabpanel).toHaveAttribute('role', 'tabpanel');
1082+
expect(tabpanel).toHaveTextContent('Tab 1 content');
1083+
}
1084+
}
1085+
});
1086+
1087+
it('renders list and panel fragment siblings in non-matching positions properly, list fragment first', function () {
1088+
let container = render(
1089+
<Provider theme={theme}>
1090+
<Tabs aria-label="Tab Example" maxWidth={500}>
1091+
<TabList>
1092+
<>
1093+
<Item>Tab 1</Item>
1094+
</>
1095+
<Item>Tab 2</Item>
1096+
</TabList>
1097+
<TabPanels>
1098+
<Item>
1099+
Tab 1 content
1100+
</Item>
1101+
<>
1102+
<Item>
1103+
Tab 2 content
1104+
</Item>
1105+
</>
1106+
</TabPanels>
1107+
</Tabs>
1108+
</Provider>
1109+
);
1110+
1111+
let tablist = container.getByRole('tablist');
1112+
expect(tablist).toBeTruthy();
1113+
1114+
expect(tablist).toHaveAttribute('aria-orientation', 'horizontal');
1115+
1116+
let tabs = within(tablist).getAllByRole('tab');
1117+
expect(tabs.length).toBe(2);
1118+
1119+
for (let tab of tabs) {
1120+
expect(tab).toHaveAttribute('tabindex');
1121+
expect(tab).toHaveAttribute('aria-selected');
1122+
let isSelected = tab.getAttribute('aria-selected') === 'true';
1123+
if (isSelected) {
1124+
expect(tab).toHaveAttribute('aria-controls');
1125+
let tabpanel = document.getElementById(tab.getAttribute('aria-controls'));
1126+
expect(tabpanel).toBeTruthy();
1127+
expect(tabpanel).toHaveAttribute('aria-labelledby', tab.id);
1128+
expect(tabpanel).toHaveAttribute('role', 'tabpanel');
1129+
expect(tabpanel).toHaveTextContent('Tab 1 content');
1130+
}
1131+
}
1132+
});
1133+
1134+
it('renders list and panel fragment siblings in non-matching positions properly, panel fragment first', function () {
1135+
let container = render(
1136+
<Provider theme={theme}>
1137+
<Tabs aria-label="Tab Example" maxWidth={500}>
1138+
<TabList>
1139+
<Item>Tab 1</Item>
1140+
<>
1141+
<Item>Tab 2</Item>
1142+
</>
1143+
</TabList>
1144+
<TabPanels>
1145+
<>
1146+
<Item>
1147+
Tab 1 content
1148+
</Item>
1149+
</>
1150+
<Item>
1151+
Tab 2 content
1152+
</Item>
1153+
</TabPanels>
1154+
</Tabs>
1155+
</Provider>
1156+
);
1157+
1158+
let tablist = container.getByRole('tablist');
1159+
expect(tablist).toBeTruthy();
1160+
1161+
expect(tablist).toHaveAttribute('aria-orientation', 'horizontal');
1162+
1163+
let tabs = within(tablist).getAllByRole('tab');
1164+
expect(tabs.length).toBe(2);
1165+
1166+
for (let tab of tabs) {
1167+
expect(tab).toHaveAttribute('tabindex');
1168+
expect(tab).toHaveAttribute('aria-selected');
1169+
let isSelected = tab.getAttribute('aria-selected') === 'true';
1170+
if (isSelected) {
1171+
expect(tab).toHaveAttribute('aria-controls');
1172+
let tabpanel = document.getElementById(tab.getAttribute('aria-controls'));
1173+
expect(tabpanel).toBeTruthy();
1174+
expect(tabpanel).toHaveAttribute('aria-labelledby', tab.id);
1175+
expect(tabpanel).toHaveAttribute('role', 'tabpanel');
1176+
expect(tabpanel).toHaveTextContent('Tab 1 content');
1177+
}
1178+
}
1179+
});
1180+
1181+
it('renders fragment with renderer properly', function () {
1182+
let container = render(
1183+
<Provider theme={theme}>
1184+
<Tabs aria-label="Tab Sample" items={defaultItems}>
1185+
<TabList>
1186+
<>
1187+
{item => (
1188+
<Item key={item.name} title={item.name || item.children} />
1189+
)}
1190+
</>
1191+
</TabList>
1192+
<TabPanels>
1193+
<>
1194+
{item => (
1195+
<Item key={item.name} title={item.name}>
1196+
{item.children}
1197+
</Item>
1198+
)}
1199+
</>
1200+
</TabPanels>
1201+
</Tabs>
1202+
</Provider>
1203+
);
1204+
1205+
let tablist = container.getByRole('tablist');
1206+
expect(tablist).toBeTruthy();
1207+
1208+
expect(tablist).toHaveAttribute('aria-orientation', 'horizontal');
1209+
1210+
let tabs = within(tablist).getAllByRole('tab');
1211+
expect(tabs.length).toBe(3);
1212+
1213+
for (let tab of tabs) {
1214+
expect(tab).toHaveAttribute('tabindex');
1215+
expect(tab).toHaveAttribute('aria-selected');
1216+
let isSelected = tab.getAttribute('aria-selected') === 'true';
1217+
if (isSelected) {
1218+
expect(tab).toHaveAttribute('aria-controls');
1219+
let tabpanel = document.getElementById(tab.getAttribute('aria-controls'));
1220+
expect(tabpanel).toBeTruthy();
1221+
expect(tabpanel).toHaveAttribute('aria-labelledby', tab.id);
1222+
expect(tabpanel).toHaveAttribute('role', 'tabpanel');
1223+
expect(tabpanel).toHaveTextContent(defaultItems[0].children);
1224+
}
1225+
}
1226+
});
1227+
1228+
it('renders fragment with mapper properly', function () {
1229+
let container = render(
1230+
<Provider theme={theme}>
1231+
<Tabs aria-label="Tab Sample">
1232+
<TabList>
1233+
<>
1234+
{defaultItems.map(item => (
1235+
<Item key={item.name} title={item.name || item.children} />
1236+
))}
1237+
</>
1238+
</TabList>
1239+
<TabPanels>
1240+
<>
1241+
{defaultItems.map(item => (
1242+
<Item key={item.name}>
1243+
{item.children}
1244+
</Item>
1245+
))}
1246+
</>
1247+
</TabPanels>
1248+
</Tabs>
1249+
</Provider>
1250+
);
1251+
1252+
let tablist = container.getByRole('tablist');
1253+
expect(tablist).toBeTruthy();
1254+
1255+
expect(tablist).toHaveAttribute('aria-orientation', 'horizontal');
1256+
1257+
let tabs = within(tablist).getAllByRole('tab');
1258+
expect(tabs.length).toBe(3);
1259+
1260+
for (let tab of tabs) {
1261+
expect(tab).toHaveAttribute('tabindex');
1262+
expect(tab).toHaveAttribute('aria-selected');
1263+
let isSelected = tab.getAttribute('aria-selected') === 'true';
1264+
if (isSelected) {
1265+
expect(tab).toHaveAttribute('aria-controls');
1266+
let tabpanel = document.getElementById(tab.getAttribute('aria-controls'));
1267+
expect(tabpanel).toBeTruthy();
1268+
expect(tabpanel).toHaveAttribute('aria-labelledby', tab.id);
1269+
expect(tabpanel).toHaveAttribute('role', 'tabpanel');
1270+
expect(tabpanel).toHaveTextContent(defaultItems[0].children);
1271+
}
1272+
}
1273+
});
1274+
});
8931275
});

0 commit comments

Comments
 (0)