Test setup for new web pages
This commit is contained in:
		
							parent
							
								
									fa8ce28f88
								
							
						
					
					
						commit
						f7e2c89e65
					
				
					 10 changed files with 233 additions and 37 deletions
				
			
		|  | @ -59,7 +59,7 @@ test("invite: checks if guild exists", async t => { // it might not exist if the | |||
| }) | ||||
| 
 | ||||
| test("invite: checks if channel exists or is autocreatable", async t => { | ||||
| 	db.prepare("UPDATE guild_active SET autocreate = 0").run() | ||||
| 	db.prepare("UPDATE guild_active SET autocreate = 0 WHERE guild_id = '112760669178241024'").run() | ||||
| 	const msgs = await fromAsync(_interact({ | ||||
| 		data: { | ||||
| 			options: [{ | ||||
|  | @ -72,7 +72,7 @@ test("invite: checks if channel exists or is autocreatable", async t => { | |||
| 		guild_id: "112760669178241024" | ||||
| 	}, {})) | ||||
| 	t.equal(msgs[0].createInteractionResponse.data.content, "This channel isn't bridged, so you can't invite Matrix users yet. Try turning on automatic room-creation or link a Matrix room in the website.") | ||||
| 	db.prepare("UPDATE guild_active SET autocreate = 1").run() | ||||
| 	db.prepare("UPDATE guild_active SET autocreate = 1 WHERE guild_id = '112760669178241024'").run() | ||||
| }) | ||||
| 
 | ||||
| test("invite: checks if user is already invited to space", async t => { | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ const getRelativePath = require("get-relative-path") | |||
| const h3 = require("h3") | ||||
| const {defineEventHandler, defaultContentType, setResponseStatus, useSession, getQuery} = h3 | ||||
| const {compileFile} = require("@cloudrac3r/pug") | ||||
| const pretty = process.argv.join(" ").includes("test") | ||||
| 
 | ||||
| const {reg} = require("../matrix/read-registration") | ||||
| 
 | ||||
|  | @ -31,7 +32,7 @@ function render(event, filename, locals) { | |||
| 
 | ||||
| 	function compile() { | ||||
| 		try { | ||||
| 			const template = compileFile(path, {}) | ||||
| 			const template = compileFile(path, {pretty}) | ||||
| 			pugCache.set(path, async (event, locals) => { | ||||
| 				defaultContentType(event, "text/html; charset=utf-8") | ||||
| 				const session = await useSession(event, {password: reg.as_token}) | ||||
|  |  | |||
|  | @ -23,3 +23,13 @@ block body | |||
|       != icons.Spots.SpotAlertXL | ||||
|       p Either the selected server doesn't exist, or you don't have the Manage Server permission on Discord. | ||||
|       p If you've checked your permissions, try #[a(href=rel("/oauth")) logging in again.] | ||||
| 
 | ||||
|   else if !row | ||||
|     .s-empty-state.wmx4.p48 | ||||
|       != icons.Spots.SpotAlertXL | ||||
|       p Please add the bot to your server using the buttons on the home page. | ||||
| 
 | ||||
|   else | ||||
|     .s-empty-state.wmx4.p48 | ||||
|       != icons.Spots.SpotAlertXL | ||||
|       p Access denied. | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ mixin space(space) | |||
|       strong= space.name | ||||
|       if space.topic | ||||
|         ul.s-user-card--awards | ||||
|           li space.topic | ||||
|           li= space.topic | ||||
| 
 | ||||
| block body | ||||
|   .s-notice.s-notice__info.d-flex.g16 | ||||
|  |  | |||
|  | @ -115,12 +115,12 @@ as.router.get("/guild", defineEventHandler(async event => { | |||
| 
 | ||||
| 	// Permission problems
 | ||||
| 	if (!guild_id || !guild || !(session.data.managedGuilds || []).concat(session.data.matrixGuilds || []).includes(guild_id) || !row) { | ||||
| 		return pugSync.render(event, "guild_access_denied.pug", {guild_id}) | ||||
| 		return pugSync.render(event, "guild_access_denied.pug", {guild_id, row}) | ||||
| 	} | ||||
| 
 | ||||
| 	// Self-service guild that hasn't been linked yet - needs a special page encouraging the link flow
 | ||||
| 	if (!row.space_id && row.autocreate === 0) { | ||||
| 		const spaces = db.prepare("SELECT room_id, type, name, avatar FROM invite LEFT JOIN guild_space ON invite.room_id = guild_space.space_id WHERE mxid = ? AND space_id IS NULL and type = 'm.space'").all(session.data.mxid) | ||||
| 		const spaces = db.prepare("SELECT room_id, type, name, topic, avatar FROM invite LEFT JOIN guild_space ON invite.room_id = guild_space.space_id WHERE mxid = ? AND space_id IS NULL and type = 'm.space'").all(session.data.mxid) | ||||
| 		return pugSync.render(event, "guild_not_linked.pug", {guild, guild_id, spaces}) | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,70 +1,96 @@ | |||
| // @ts-check
 | ||||
| 
 | ||||
| const tryToCatch = require("try-to-catch") | ||||
| const {test} = require("supertape") | ||||
| const {router} = require("../../../test/web") | ||||
| const {router, test} = require("../../../test/web") | ||||
| const {MatrixServerError} = require("../../matrix/mreq") | ||||
| 
 | ||||
| let nonce | ||||
| 
 | ||||
| test("web guild: access denied when not logged in", async t => { | ||||
| 	const content = await router.test("get", "/guild?guild_id=112760669178241024", { | ||||
| 	const html = await router.test("get", "/guild?guild_id=112760669178241024", { | ||||
| 		sessionData: { | ||||
| 		}, | ||||
| 	}) | ||||
| 	t.match(content, /You need to log in to manage your servers./) | ||||
| 	t.match(html, /You need to log in to manage your servers./) | ||||
| }) | ||||
| 
 | ||||
| test("web guild: asks to select guild if not selected", async t => { | ||||
| 	const content = await router.test("get", "/guild", { | ||||
| 	const html = await router.test("get", "/guild", { | ||||
| 		sessionData: { | ||||
| 			user_id: "1", | ||||
| 			managedGuilds: [] | ||||
| 		}, | ||||
| 	}) | ||||
| 	t.match(content, /Select a server from the top right corner to continue./) | ||||
| 	t.match(html, /Select a server from the top right corner to continue./) | ||||
| }) | ||||
| 
 | ||||
| test("web guild: access denied when guild id messed up", async t => { | ||||
| 	const content = await router.test("get", "/guild?guild_id=1", { | ||||
| 	const html = await router.test("get", "/guild?guild_id=1", { | ||||
| 		sessionData: { | ||||
| 			user_id: "1", | ||||
| 			managedGuilds: [] | ||||
| 		}, | ||||
| 	}) | ||||
| 	t.match(content, /the selected server doesn't exist/) | ||||
| 	t.match(html, /the selected server doesn't exist/) | ||||
| }) | ||||
| 
 | ||||
| test("web invite: access denied with invalid nonce", async t => { | ||||
| 	const content = await router.test("get", "/invite?nonce=1") | ||||
| 	t.match(content, /This QR code has expired./) | ||||
| 	const html = await router.test("get", "/invite?nonce=1") | ||||
| 	t.match(html, /This QR code has expired./) | ||||
| }) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| test("web guild: can view unbridged guild", async t => { | ||||
| 	const content = await router.test("get", "/guild?guild_id=66192955777486848", { | ||||
| 	const html = await router.test("get", "/guild?guild_id=66192955777486848", { | ||||
| 		sessionData: { | ||||
| 			user_id: "1", | ||||
| 			managedGuilds: ["66192955777486848"] | ||||
| 		}, | ||||
| 		api: { | ||||
| 			async getStateEvent(roomID, type, key) { | ||||
| 				return {} | ||||
| 			}, | ||||
| 			async getMembers(roomID, membership) { | ||||
| 				return {chunk: []} | ||||
| 			}, | ||||
| 			async getFullHierarchy(roomID) { | ||||
| 				return [] | ||||
| 			} | ||||
| 		} | ||||
| 	}) | ||||
| 	t.match(content, /<h1[^<]*Function & Arg/) | ||||
| 	t.has(html, `<h1 class="s-page-title--header">Function & Arg</h1>`) | ||||
| }) | ||||
| 
 | ||||
| test("web guild: unbridged self-service guild prompts log in to matrix", async t => { | ||||
| 	const html = await router.test("get", "/guild?guild_id=665289423482519565", { | ||||
| 		sessionData: { | ||||
| 			user_id: "1", | ||||
| 			managedGuilds: ["665289423482519565"] | ||||
| 		} | ||||
| 	}) | ||||
| 	t.has(html, `You picked self-service mode`) | ||||
| 	t.has(html, `You need to log in with Matrix first`) | ||||
| }) | ||||
| 
 | ||||
| test("web guild: unbridged self-service guild asks to be invited", async t => { | ||||
| 	const html = await router.test("get", "/guild?guild_id=665289423482519565", { | ||||
| 		sessionData: { | ||||
| 			mxid: "@user:example.org", | ||||
| 			user_id: "1", | ||||
| 			managedGuilds: ["665289423482519565"] | ||||
| 		} | ||||
| 	}) | ||||
| 	t.has(html, `On Matrix, invite <`) | ||||
| }) | ||||
| 
 | ||||
| test("web guild: unbridged self-service guild shows available spaces", async t => { | ||||
| 	const html = await router.test("get", "/guild?guild_id=665289423482519565", { | ||||
| 		sessionData: { | ||||
| 			mxid: "@cadence:cadence.moe", | ||||
| 			user_id: "1", | ||||
| 			managedGuilds: ["665289423482519565"] | ||||
| 		} | ||||
| 	}) | ||||
| 	t.has(html, `<strong>Data Horde</strong>`) | ||||
| 	t.has(html, `<li>here is the space topic</li>`) | ||||
| 	// t.match(html, /<img class="avatar-image" src="https:\/\/bridge.cadence.moe\/download\/matrix\/cadence.moe\/TLqQOsTSrZkVKwBSWYTZNTrw">/)
 | ||||
| 	// t.notMatch(html, /<strong>some room<\/strong>/)
 | ||||
| 	// t.notMatch(html, /<strong>somebody else's space<\/strong>/)
 | ||||
| }) | ||||
| 
 | ||||
| 
 | ||||
| test("web guild: can view bridged guild", async t => { | ||||
| 	const content = await router.test("get", "/guild?guild_id=112760669178241024", { | ||||
| 	const html = await router.test("get", "/guild?guild_id=112760669178241024", { | ||||
| 		sessionData: { | ||||
| 			managedGuilds: ["112760669178241024"] | ||||
| 		}, | ||||
|  | @ -80,14 +106,14 @@ test("web guild: can view bridged guild", async t => { | |||
| 			} | ||||
| 		} | ||||
| 	}) | ||||
| 	t.match(content, /<h1[^<]*Psychonauts 3/) | ||||
| 	nonce = content.match(/data-nonce="([a-f0-9-]+)"/)?.[1] | ||||
| 	t.match(html, /<h1[^<]*Psychonauts 3/) | ||||
| 	nonce = html.match(/data-nonce="([a-f0-9-]+)"/)?.[1] | ||||
| 	t.ok(nonce) | ||||
| }) | ||||
| 
 | ||||
| test("web invite: page loads with valid nonce", async t => { | ||||
| 	const content = await router.test("get", `/invite?nonce=${nonce}`) | ||||
| 	t.match(content, /Invite a Matrix user/) | ||||
| 	const html = await router.test("get", `/invite?nonce=${nonce}`) | ||||
| 	t.match(html, /Invite a Matrix user/) | ||||
| }) | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										119
									
								
								test/data.js
									
										
									
									
									
								
							
							
						
						
									
										119
									
								
								test/data.js
									
										
									
									
									
								
							|  | @ -18,6 +18,20 @@ module.exports = { | |||
| 			id: "112760669178241024", | ||||
| 			default_thread_rate_limit_per_user: 0, | ||||
| 			guild_id: "112760669178241024" | ||||
| 		}, | ||||
| 		saving_the_world: { | ||||
| 			type: 0, | ||||
| 			topic: "Anything and everything archiving/preservation related", | ||||
| 			rate_limit_per_user: 0, | ||||
| 			position: 0, | ||||
| 			permission_overwrites: [], | ||||
| 			parent_id: "665289423482519566", | ||||
| 			name: "saving-the-world", | ||||
| 			last_pin_timestamp: "2021-04-14T18:39:41+00:00", | ||||
| 			last_message_id: "1335828749479837750", | ||||
| 			id: "665310973967597573", | ||||
| 			flags: 0, | ||||
| 			guild_id: "665289423482519565" | ||||
| 		} | ||||
| 	}, | ||||
| 	room: { | ||||
|  | @ -252,6 +266,111 @@ module.exports = { | |||
| 			nsfw: false, | ||||
| 			safety_alerts_channel_id: null, | ||||
| 			lazy: true | ||||
| 		}, | ||||
| 		data_horde: { | ||||
| 			preferred_locale: "en-US", | ||||
| 			afk_channel_id: null, | ||||
| 			profile: null, | ||||
| 			owner_id: "222343226990788609", | ||||
| 			soundboard_sounds: [], | ||||
| 			hub_type: null, | ||||
| 			mfa_level: 0, | ||||
| 			activity_instances: [], | ||||
| 			inventory_settings: null, | ||||
| 			voice_states: [], | ||||
| 			system_channel_id: "675397790204952636", | ||||
| 			id: "665289423482519565", | ||||
| 			member_count: 138, | ||||
| 			clan: null, | ||||
| 			default_message_notifications: 1, | ||||
| 			name: "Data Horde", | ||||
| 			banner: null, | ||||
| 			premium_subscription_count: 0, | ||||
| 			max_stage_video_channel_users: 50, | ||||
| 			max_members: 500000, | ||||
| 			incidents_data: null, | ||||
| 			joined_at: "2020-05-10T02:00:10.646000+00:00", | ||||
| 			unavailable: false, | ||||
| 			discovery_splash: null, | ||||
| 			threads: [], | ||||
| 			system_channel_flags: 0, | ||||
| 			safety_alerts_channel_id: null, | ||||
| 			nsfw: false, | ||||
| 			nsfw_level: 0, | ||||
| 			stage_instances: [], | ||||
| 			large: false, | ||||
| 			icon: "d7c4bdb35c10f21e475a50fb205d5c32", | ||||
| 			roles: [ | ||||
| 				{ | ||||
| 					version: 1683238686112, | ||||
| 					unicode_emoji: null, | ||||
| 					tags: {}, | ||||
| 					position: 0, | ||||
| 					permissions: "2221982107557441", | ||||
| 					name: "@everyone", | ||||
| 					mentionable: false, | ||||
| 					managed: false, | ||||
| 					id: "665289423482519565", | ||||
| 					icon: null, | ||||
| 					hoist: false, | ||||
| 					flags: 0, | ||||
| 					color: 0 | ||||
| 				}, | ||||
| 				{ | ||||
| 					version: 1683791258594, | ||||
| 					unicode_emoji: null, | ||||
| 					tags: {}, | ||||
| 					position: 22, | ||||
| 					permissions: "7515668211", | ||||
| 					name: "Founder", | ||||
| 					mentionable: true, | ||||
| 					managed: false, | ||||
| 					id: "665290147377578005", | ||||
| 					icon: null, | ||||
| 					hoist: false, | ||||
| 					flags: 0, | ||||
| 					color: 1752220 | ||||
| 				}, | ||||
| 				{ | ||||
| 					version: 1683791258580, | ||||
| 					unicode_emoji: null, | ||||
| 					tags: {}, | ||||
| 					position: 19, | ||||
| 					permissions: "6546775617", | ||||
| 					name: "Gaming Alexandria", | ||||
| 					mentionable: false, | ||||
| 					managed: false, | ||||
| 					id: "684524730274807911", | ||||
| 					icon: null, | ||||
| 					hoist: false, | ||||
| 					flags: 0, | ||||
| 					color: 15844367 | ||||
| 				} | ||||
| 			], | ||||
| 			description: null, | ||||
| 			afk_timeout: 300, | ||||
| 			verification_level: 1, | ||||
| 			latest_onboarding_question_id: null, | ||||
| 			guild_scheduled_events: [], | ||||
| 			rules_channel_id: null, | ||||
| 			embedded_activities: [], | ||||
| 			region: "deprecated", | ||||
| 			vanity_url_code: null, | ||||
| 			application_id: null, | ||||
| 			premium_tier: 0, | ||||
| 			explicit_content_filter: 0, | ||||
| 			stickers: [], | ||||
| 			public_updates_channel_id: null, | ||||
| 			splash: null, | ||||
| 			premium_progress_bar_enabled: false, | ||||
| 			features: [], | ||||
| 			lazy: true, | ||||
| 			max_video_channel_users: 25, | ||||
| 			application_command_counts: {}, | ||||
| 			home_header: null, | ||||
| 			version: 1717720047590, | ||||
| 			emojis: [], | ||||
| 			presences: [] | ||||
| 		} | ||||
| 	}, | ||||
| 	user: { | ||||
|  |  | |||
|  | @ -1,7 +1,9 @@ | |||
| BEGIN TRANSACTION; | ||||
| 
 | ||||
| INSERT INTO guild_active (guild_id, autocreate) VALUES | ||||
| ('112760669178241024', 1); | ||||
| ('112760669178241024', 1), | ||||
| ('66192955777486848', 1), | ||||
| ('665289423482519565', 0); | ||||
| 
 | ||||
| INSERT INTO guild_space (guild_id, space_id, privacy_level) VALUES | ||||
| ('112760669178241024', '!jjWAGMeQdNrVZSSfvz:cadence.moe', 0); | ||||
|  | @ -171,4 +173,9 @@ INSERT INTO media_proxy (permitted_hash) VALUES | |||
| (-429802515645771439), | ||||
| (4558604729745184757); | ||||
| 
 | ||||
| INSERT INTO invite (mxid, room_id, type, name, avatar, topic) VALUES | ||||
| ('@cadence:cadence.moe', '!zTMspHVUBhFLLSdmnS:cadence.moe', 'm.space', 'Data Horde', 'mxc://cadence.moe/TLqQOsTSrZkVKwBSWYTZNTrw', 'here is the space topic'), | ||||
| ('@cadence:cadence.moe', '!room:cadence.moe', NULL, 'some room', NULL, NULL), | ||||
| ('@rnl:cadence.moe', '!space:cadence.moe', NULL, 'somebody else''s space', NULL, NULL); | ||||
| 
 | ||||
| COMMIT; | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ const stp = require("stream").promises | |||
| const sqlite = require("better-sqlite3") | ||||
| const migrate = require("../src/db/migrate") | ||||
| const HeatSync = require("heatsync") | ||||
| const {test} = require("supertape") | ||||
| const {test, extend} = require("supertape") | ||||
| const data = require("./data") | ||||
| /** @type {import("node-fetch").default} */ | ||||
| // @ts-ignore
 | ||||
|  | @ -31,10 +31,12 @@ const discord = { | |||
| 	guilds: new Map([ | ||||
| 		[data.guild.general.id, data.guild.general], | ||||
| 		[data.guild.fna.id, data.guild.fna], | ||||
| 		[data.guild.data_horde.id, data.guild.data_horde] | ||||
| 	]), | ||||
| 	guildChannelMap: new Map([ | ||||
| 		[data.guild.general.id, [data.channel.general.id]], | ||||
| 		[data.guild.fna.id, []], | ||||
| 		[data.guild.data_horde.id, [data.channel.saving_the_world.id]] | ||||
| 	]), | ||||
| 	application: { | ||||
| 		id: "684280192553844747" | ||||
|  | @ -47,7 +49,8 @@ const discord = { | |||
| 		["498323546729086986", { | ||||
| 			guild_id: "497159726455455754", | ||||
| 			name: "bad-boots-prison" | ||||
| 		}] | ||||
| 		}], | ||||
| 		[data.channel.saving_the_world.id, data.channel.saving_the_world] | ||||
| 	]) | ||||
| } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										30
									
								
								test/web.js
									
										
									
									
									
								
							
							
						
						
									
										30
									
								
								test/web.js
									
										
									
									
									
								
							|  | @ -2,6 +2,35 @@ const passthrough = require("../src/passthrough") | |||
| const h3 = require("h3") | ||||
| const http = require("http") | ||||
| const {SnowTransfer} = require("snowtransfer") | ||||
| const assert = require("assert").strict | ||||
| const domino = require("domino") | ||||
| const {extend} = require("supertape") | ||||
| 
 | ||||
| /** | ||||
|  * @param {string} html | ||||
|  */ | ||||
| function getContent(html) { | ||||
| 	const doc = domino.createDocument(html) | ||||
| 	doc.querySelectorAll("svg").cache.forEach(e => e.remove()) | ||||
| 	const content = doc.getElementById("content") | ||||
| 	assert(content) | ||||
| 	return content.innerHTML.trim() | ||||
| } | ||||
| 
 | ||||
| const test = extend({ | ||||
| 	has: operator => /** @param {string | RegExp} expected */ (html, expected, message = "should have substring in html content") => { | ||||
| 		const content = getContent(html) | ||||
| 		const is = expected instanceof RegExp ? content.match(expected) : content.includes(expected) | ||||
| 		const {output, result} = operator.equal(content, expected.toString()) | ||||
| 		return { | ||||
| 			expected: expected.toString(), | ||||
| 			message, | ||||
| 			is, | ||||
| 			result: result, | ||||
| 			output: output | ||||
| 		} | ||||
| 	} | ||||
| }) | ||||
| 
 | ||||
| class Router { | ||||
| 	constructor() { | ||||
|  | @ -67,3 +96,4 @@ const router = new Router() | |||
| passthrough.as = {router} | ||||
| 
 | ||||
| module.exports.router = router | ||||
| module.exports.test = test | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue