trailing-slash.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. import nodejs from '../dist/index.js';
  2. import { loadFixture } from './test-utils.js';
  3. import { expect } from 'chai';
  4. import * as cheerio from 'cheerio';
  5. /**
  6. * @typedef {import('../../../astro/test/test-utils').Fixture} Fixture
  7. */
  8. async function load() {
  9. const mod = await import(
  10. `./fixtures/trailing-slash/dist/server/entry.mjs?dropcache=${Date.now()}`
  11. );
  12. return mod;
  13. }
  14. describe('Trailing slash', () => {
  15. /** @type {import('./test-utils').Fixture} */
  16. let fixture;
  17. let server;
  18. describe('Always', async () => {
  19. describe('With base', async () => {
  20. before(async () => {
  21. process.env.ASTRO_NODE_AUTOSTART = 'disabled';
  22. process.env.PRERENDER = true;
  23. fixture = await loadFixture({
  24. root: './fixtures/trailing-slash/',
  25. base: '/some-base',
  26. output: 'hybrid',
  27. trailingSlash: 'always',
  28. adapter: nodejs({ mode: 'standalone' }),
  29. });
  30. await fixture.build();
  31. const { startServer } = await load();
  32. let res = startServer();
  33. server = res.server;
  34. });
  35. after(async () => {
  36. await server.stop();
  37. await fixture.clean();
  38. delete process.env.PRERENDER;
  39. });
  40. it('Can render prerendered base route', async () => {
  41. const res = await fetch(`http://${server.host}:${server.port}`);
  42. const html = await res.text();
  43. const $ = cheerio.load(html);
  44. expect(res.status).to.equal(200);
  45. expect($('h1').text()).to.equal('Index');
  46. });
  47. it('Can render prerendered route with redirect', async () => {
  48. const res = await fetch(`http://${server.host}:${server.port}/some-base/one`, {
  49. redirect: 'manual',
  50. });
  51. expect(res.status).to.equal(301);
  52. expect(res.headers.get('location')).to.equal('/some-base/one/');
  53. });
  54. it('Can render prerendered route with redirect and query params', async () => {
  55. const res = await fetch(`http://${server.host}:${server.port}/some-base/one?foo=bar`, {
  56. redirect: 'manual',
  57. });
  58. expect(res.status).to.equal(301);
  59. expect(res.headers.get('location')).to.equal('/some-base/one/?foo=bar');
  60. });
  61. it('Can render prerendered route with query params', async () => {
  62. const res = await fetch(`http://${server.host}:${server.port}/some-base/one/?foo=bar`);
  63. const html = await res.text();
  64. const $ = cheerio.load(html);
  65. expect(res.status).to.equal(200);
  66. expect($('h1').text()).to.equal('One');
  67. });
  68. });
  69. describe('Without base', async () => {
  70. before(async () => {
  71. process.env.ASTRO_NODE_AUTOSTART = 'disabled';
  72. process.env.PRERENDER = true;
  73. fixture = await loadFixture({
  74. root: './fixtures/trailing-slash/',
  75. output: 'hybrid',
  76. trailingSlash: 'always',
  77. adapter: nodejs({ mode: 'standalone' }),
  78. });
  79. await fixture.build();
  80. const { startServer } = await load();
  81. let res = startServer();
  82. server = res.server;
  83. });
  84. after(async () => {
  85. await server.stop();
  86. await fixture.clean();
  87. delete process.env.PRERENDER;
  88. });
  89. it('Can render prerendered base route', async () => {
  90. const res = await fetch(`http://${server.host}:${server.port}`);
  91. const html = await res.text();
  92. const $ = cheerio.load(html);
  93. expect(res.status).to.equal(200);
  94. expect($('h1').text()).to.equal('Index');
  95. });
  96. it('Can render prerendered route with redirect', async () => {
  97. const res = await fetch(`http://${server.host}:${server.port}/one`, {
  98. redirect: 'manual',
  99. });
  100. expect(res.status).to.equal(301);
  101. expect(res.headers.get('location')).to.equal('/one/');
  102. });
  103. it('Can render prerendered route with redirect and query params', async () => {
  104. const res = await fetch(`http://${server.host}:${server.port}/one?foo=bar`, {
  105. redirect: 'manual',
  106. });
  107. expect(res.status).to.equal(301);
  108. expect(res.headers.get('location')).to.equal('/one/?foo=bar');
  109. });
  110. it('Can render prerendered route with query params', async () => {
  111. const res = await fetch(`http://${server.host}:${server.port}/one/?foo=bar`);
  112. const html = await res.text();
  113. const $ = cheerio.load(html);
  114. expect(res.status).to.equal(200);
  115. expect($('h1').text()).to.equal('One');
  116. });
  117. });
  118. });
  119. describe('Never', async () => {
  120. describe('With base', async () => {
  121. before(async () => {
  122. process.env.ASTRO_NODE_AUTOSTART = 'disabled';
  123. process.env.PRERENDER = true;
  124. fixture = await loadFixture({
  125. root: './fixtures/trailing-slash/',
  126. base: '/some-base',
  127. output: 'hybrid',
  128. trailingSlash: 'never',
  129. adapter: nodejs({ mode: 'standalone' }),
  130. });
  131. await fixture.build();
  132. const { startServer } = await load();
  133. let res = startServer();
  134. server = res.server;
  135. });
  136. after(async () => {
  137. await server.stop();
  138. await fixture.clean();
  139. delete process.env.PRERENDER;
  140. });
  141. it('Can render prerendered base route', async () => {
  142. const res = await fetch(`http://${server.host}:${server.port}`);
  143. const html = await res.text();
  144. const $ = cheerio.load(html);
  145. expect(res.status).to.equal(200);
  146. expect($('h1').text()).to.equal('Index');
  147. });
  148. it('Can render prerendered route with redirect', async () => {
  149. const res = await fetch(`http://${server.host}:${server.port}/some-base/one/`, {
  150. redirect: 'manual',
  151. });
  152. expect(res.status).to.equal(301);
  153. expect(res.headers.get('location')).to.equal('/some-base/one');
  154. });
  155. it('Can render prerendered route with redirect and query params', async () => {
  156. const res = await fetch(`http://${server.host}:${server.port}/some-base/one/?foo=bar`, {
  157. redirect: 'manual',
  158. });
  159. expect(res.status).to.equal(301);
  160. expect(res.headers.get('location')).to.equal('/some-base/one?foo=bar');
  161. });
  162. it('Can render prerendered route with query params', async () => {
  163. const res = await fetch(`http://${server.host}:${server.port}/some-base/one?foo=bar`);
  164. const html = await res.text();
  165. const $ = cheerio.load(html);
  166. expect(res.status).to.equal(200);
  167. expect($('h1').text()).to.equal('One');
  168. });
  169. });
  170. describe('Without base', async () => {
  171. before(async () => {
  172. process.env.ASTRO_NODE_AUTOSTART = 'disabled';
  173. process.env.PRERENDER = true;
  174. fixture = await loadFixture({
  175. root: './fixtures/trailing-slash/',
  176. output: 'hybrid',
  177. trailingSlash: 'never',
  178. adapter: nodejs({ mode: 'standalone' }),
  179. });
  180. await fixture.build();
  181. const { startServer } = await load();
  182. let res = startServer();
  183. server = res.server;
  184. });
  185. after(async () => {
  186. await server.stop();
  187. await fixture.clean();
  188. delete process.env.PRERENDER;
  189. });
  190. it('Can render prerendered base route', async () => {
  191. const res = await fetch(`http://${server.host}:${server.port}`);
  192. const html = await res.text();
  193. const $ = cheerio.load(html);
  194. expect(res.status).to.equal(200);
  195. expect($('h1').text()).to.equal('Index');
  196. });
  197. it('Can render prerendered route with redirect', async () => {
  198. const res = await fetch(`http://${server.host}:${server.port}/one/`, {
  199. redirect: 'manual',
  200. });
  201. expect(res.status).to.equal(301);
  202. expect(res.headers.get('location')).to.equal('/one');
  203. });
  204. it('Can render prerendered route with redirect and query params', async () => {
  205. const res = await fetch(`http://${server.host}:${server.port}/one/?foo=bar`, {
  206. redirect: 'manual',
  207. });
  208. expect(res.status).to.equal(301);
  209. expect(res.headers.get('location')).to.equal('/one?foo=bar');
  210. });
  211. it('Can render prerendered route and query params', async () => {
  212. const res = await fetch(`http://${server.host}:${server.port}/one?foo=bar`);
  213. const html = await res.text();
  214. const $ = cheerio.load(html);
  215. expect(res.status).to.equal(200);
  216. expect($('h1').text()).to.equal('One');
  217. });
  218. });
  219. });
  220. describe('Ignore', async () => {
  221. describe('With base', async () => {
  222. before(async () => {
  223. process.env.ASTRO_NODE_AUTOSTART = 'disabled';
  224. process.env.PRERENDER = true;
  225. fixture = await loadFixture({
  226. root: './fixtures/trailing-slash/',
  227. base: '/some-base',
  228. output: 'hybrid',
  229. trailingSlash: 'ignore',
  230. adapter: nodejs({ mode: 'standalone' }),
  231. });
  232. await fixture.build();
  233. const { startServer } = await load();
  234. let res = startServer();
  235. server = res.server;
  236. });
  237. after(async () => {
  238. await server.stop();
  239. await fixture.clean();
  240. delete process.env.PRERENDER;
  241. });
  242. it('Can render prerendered base route', async () => {
  243. const res = await fetch(`http://${server.host}:${server.port}`);
  244. const html = await res.text();
  245. const $ = cheerio.load(html);
  246. expect(res.status).to.equal(200);
  247. expect($('h1').text()).to.equal('Index');
  248. });
  249. it('Can render prerendered route with slash', async () => {
  250. const res = await fetch(`http://${server.host}:${server.port}/some-base/one/`, {
  251. redirect: 'manual',
  252. });
  253. const html = await res.text();
  254. const $ = cheerio.load(html);
  255. expect(res.status).to.equal(200);
  256. expect($('h1').text()).to.equal('One');
  257. });
  258. it('Can render prerendered route without slash', async () => {
  259. const res = await fetch(`http://${server.host}:${server.port}/some-base/one`, {
  260. redirect: 'manual',
  261. });
  262. const html = await res.text();
  263. const $ = cheerio.load(html);
  264. expect(res.status).to.equal(200);
  265. expect($('h1').text()).to.equal('One');
  266. });
  267. it('Can render prerendered route with slash and query params', async () => {
  268. const res = await fetch(`http://${server.host}:${server.port}/some-base/one/?foo=bar`, {
  269. redirect: 'manual',
  270. });
  271. const html = await res.text();
  272. const $ = cheerio.load(html);
  273. expect(res.status).to.equal(200);
  274. expect($('h1').text()).to.equal('One');
  275. });
  276. it('Can render prerendered route without slash and with query params', async () => {
  277. const res = await fetch(`http://${server.host}:${server.port}/some-base/one?foo=bar`, {
  278. redirect: 'manual',
  279. });
  280. const html = await res.text();
  281. const $ = cheerio.load(html);
  282. expect(res.status).to.equal(200);
  283. expect($('h1').text()).to.equal('One');
  284. });
  285. });
  286. describe('Without base', async () => {
  287. before(async () => {
  288. process.env.ASTRO_NODE_AUTOSTART = 'disabled';
  289. process.env.PRERENDER = true;
  290. fixture = await loadFixture({
  291. root: './fixtures/trailing-slash/',
  292. output: 'hybrid',
  293. trailingSlash: 'ignore',
  294. adapter: nodejs({ mode: 'standalone' }),
  295. });
  296. await fixture.build();
  297. const { startServer } = await load();
  298. let res = startServer();
  299. server = res.server;
  300. });
  301. after(async () => {
  302. await server.stop();
  303. await fixture.clean();
  304. delete process.env.PRERENDER;
  305. });
  306. it('Can render prerendered base route', async () => {
  307. const res = await fetch(`http://${server.host}:${server.port}`);
  308. const html = await res.text();
  309. const $ = cheerio.load(html);
  310. expect(res.status).to.equal(200);
  311. expect($('h1').text()).to.equal('Index');
  312. });
  313. it('Can render prerendered route with slash', async () => {
  314. const res = await fetch(`http://${server.host}:${server.port}/one/`);
  315. const html = await res.text();
  316. const $ = cheerio.load(html);
  317. expect(res.status).to.equal(200);
  318. expect($('h1').text()).to.equal('One');
  319. });
  320. it('Can render prerendered route without slash', async () => {
  321. const res = await fetch(`http://${server.host}:${server.port}/one`);
  322. const html = await res.text();
  323. const $ = cheerio.load(html);
  324. expect(res.status).to.equal(200);
  325. expect($('h1').text()).to.equal('One');
  326. });
  327. it('Can render prerendered route with slash and query params', async () => {
  328. const res = await fetch(`http://${server.host}:${server.port}/one/?foo=bar`, {
  329. redirect: 'manual',
  330. });
  331. const html = await res.text();
  332. const $ = cheerio.load(html);
  333. expect(res.status).to.equal(200);
  334. expect($('h1').text()).to.equal('One');
  335. });
  336. it('Can render prerendered route without slash and with query params', async () => {
  337. const res = await fetch(`http://${server.host}:${server.port}/one?foo=bar`);
  338. const html = await res.text();
  339. const $ = cheerio.load(html);
  340. expect(res.status).to.equal(200);
  341. expect($('h1').text()).to.equal('One');
  342. });
  343. });
  344. });
  345. });