From c9c893592730d6e7f1e481cf7a78ceaf294f71ba Mon Sep 17 00:00:00 2001 From: Vincent Michel <vxgmichel@gmail.com> Date: Fri, 17 Jan 2025 16:02:56 +0100 Subject: [PATCH 1/5] Hotfix to sleep forever in web implementation of sleep --- libparsec/crates/platform_async/src/web/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libparsec/crates/platform_async/src/web/mod.rs b/libparsec/crates/platform_async/src/web/mod.rs index 476a0ec3fb7..0855a6c349a 100644 --- a/libparsec/crates/platform_async/src/web/mod.rs +++ b/libparsec/crates/platform_async/src/web/mod.rs @@ -13,6 +13,18 @@ pub async fn sleep(duration: std::time::Duration) { // Cannot use `tokio::time::sleep` since it depends on a timer API that is // not provided by `wasm32-unknown-unknown`. // Instead we use `gloo_timers` that is a convenient wrapper around js_sys. + + // Hotfix: sleep forever if Duration is MAX + // In practice, gloo_timers::future::sleep panics if the duration cannot be casted into a u32 in milliseconds. + // TODO: divide the duration in u32::MAX chunks and sleep for each chunk + if duration == std::time::Duration::MAX { + loop { + let not_send_future = + gloo_timers::future::sleep(std::time::Duration::from_secs_f64(1.0)); + pretend_future_is_send_on_web(not_send_future).await + } + return; + } let not_send_future = gloo_timers::future::sleep(duration); pretend_future_is_send_on_web(not_send_future).await } From 82ae503fb0e14199807e2ce6f40bf6d2d8f6b331 Mon Sep 17 00:00:00 2001 From: Emmanuel Leblond <emmanuel.leblond@gmail.com> Date: Fri, 17 Jan 2025 17:09:24 +0100 Subject: [PATCH 2/5] Proper fix to correct libparsec_platform_async's sleep forever on web --- .../crates/platform_async/src/web/mod.rs | 40 +++++++++++++------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/libparsec/crates/platform_async/src/web/mod.rs b/libparsec/crates/platform_async/src/web/mod.rs index 0855a6c349a..c5810803d9e 100644 --- a/libparsec/crates/platform_async/src/web/mod.rs +++ b/libparsec/crates/platform_async/src/web/mod.rs @@ -14,19 +14,33 @@ pub async fn sleep(duration: std::time::Duration) { // not provided by `wasm32-unknown-unknown`. // Instead we use `gloo_timers` that is a convenient wrapper around js_sys. - // Hotfix: sleep forever if Duration is MAX - // In practice, gloo_timers::future::sleep panics if the duration cannot be casted into a u32 in milliseconds. - // TODO: divide the duration in u32::MAX chunks and sleep for each chunk - if duration == std::time::Duration::MAX { - loop { - let not_send_future = - gloo_timers::future::sleep(std::time::Duration::from_secs_f64(1.0)); - pretend_future_is_send_on_web(not_send_future).await - } - return; - } - let not_send_future = gloo_timers::future::sleep(duration); - pretend_future_is_send_on_web(not_send_future).await + pretend_future_is_send_on_web(async { + // There is two issues here: + // - `gloo_timers` requires a u32 as duration in milliseconds which is smaller (~49 days) + // than what `std::time::Duration` can represent (~584,942,417,355 years). + // - The Javascript timeout API internally uses a i32 to store the duration in + // milliseconds (~24 days), leading to an instantaneous wake up if `gloo_timers`'s + // u32 represents a value too large. + // + // Realistically, all sleep are below 24 days so those issues are not a problem... + // unless when sleeping forever, since we use `std::time::Duration::MAX` in this case! + // + // So the solution is to consider everything above 24 days as an infinite sleep. + // + // see: + // - https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout#maximum_delay_value0 + // - https://github.com/rustwasm/gloo/issues/121 + match i32::try_from(duration.as_millis()) { + Ok(millis) => { + gloo_timers::future::TimeoutFuture::new(millis as u32).await; + } + // Sleep is bigger than 24 days, consider it is a sleep forever then ! + Err(_) => loop { + gloo_timers::future::TimeoutFuture::new(i32::MAX as u32).await; + }, + }; + }) + .await } #[inline(always)] From 0e8fb31321678f549006c0b2ebad3c3444ca5c39 Mon Sep 17 00:00:00 2001 From: Emmanuel Leblond <emmanuel.leblond@gmail.com> Date: Mon, 20 Jan 2025 12:21:05 +0100 Subject: [PATCH 3/5] Use BigInt for u64/i64 bindings --- .../templates/binding_electron_meths.rs.j2 | 24 +++++++------------ .../templates/binding_web_meths.rs.j2 | 16 ++++--------- .../templates/client_plugin_definitions.ts.j2 | 9 ++++++- 3 files changed, 20 insertions(+), 29 deletions(-) diff --git a/bindings/generator/templates/binding_electron_meths.rs.j2 b/bindings/generator/templates/binding_electron_meths.rs.j2 index 39ccc4afc9a..201d240e1e4 100644 --- a/bindings/generator/templates/binding_electron_meths.rs.j2 +++ b/bindings/generator/templates/binding_electron_meths.rs.j2 @@ -24,8 +24,10 @@ JsValue JsNull {%- elif type.kind == "bool" -%} JsBoolean -{%- elif type.kind in ("u8_based", "i32_based", "u32_based", "i64_based", "u64_based", "f64_based", "float") -%} +{%- elif type.kind in ("u8_based", "i32_based", "u32_based", "f64_based", "float") -%} JsNumber +{%- elif type.kind in ("i64_based", "u64_based") -%} +JsBigInt {%- elif type.kind in ("str", "str_based") -%} JsString {%- elif type.kind in ("bytes", "bytes_based") -%} @@ -207,11 +209,7 @@ JsString } {%- elif type.kind == "i64_based" -%} { - let v = {{ js_val }}.value({{ mut_cx_ref }}); - if v < (i64::MIN as f64) || (i64::MAX as f64) < v { - cx.throw_type_error("Not an i64 number")? - } - let v = v as i64; + let v = {{ js_val }}.to_i64({{ mut_cx_ref }}).or_else(|_| cx.throw_type_error("Not an i64 number"))?; {% if type.custom_from_rs_i64 -%} let custom_from_rs_i64 = {{ type.custom_from_rs_i64 }}; match custom_from_rs_i64(v) { @@ -224,11 +222,7 @@ JsString } {%- elif type.kind == "u64_based" -%} { - let v = {{ js_val }}.value({{ mut_cx_ref }}); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - cx.throw_type_error("Not an u64 number")? - } - let v = v as u64; + let v = {{ js_val }}.to_u64({{ mut_cx_ref }}).or_else(|_| cx.throw_type_error("Not an u64 number"))?; {% if type.custom_from_rs_u64 -%} let custom_from_rs_u64 = {{ type.custom_from_rs_u64 }}; match custom_from_rs_u64(v) { @@ -478,7 +472,7 @@ JsNumber::new({{ mut_cx_ref }}, as f64 ) {%- elif type.kind == "u64_based" -%} -JsNumber::new({{ mut_cx_ref }}, +JsBigInt::from_u64({{ mut_cx_ref }}, {%- if type.custom_to_rs_u64 -%} { let custom_to_rs_u64 = {{ type.custom_to_rs_u64 }}; @@ -490,10 +484,9 @@ JsNumber::new({{ mut_cx_ref }}, {%- else -%} {{ rs_value }} {%- endif %} - as f64 ) {%- elif type.kind == "i64_based" -%} -JsNumber::new({{ mut_cx_ref }}, +JsBigInt::from_i64({{ mut_cx_ref }}, {%- if type.custom_to_rs_i64 -%} { let custom_to_rs_i64 = {{ type.custom_to_rs_i64 }}; @@ -505,7 +498,6 @@ JsNumber::new({{ mut_cx_ref }}, {%- else -%} {{ rs_value }} {%- endif %} - as f64 ) {%- elif type.kind == "f64_based" -%} JsNumber::new({{ mut_cx_ref }}, @@ -880,7 +872,7 @@ fn {{ meth.name }}(mut cx: FunctionContext) -> JsResult<JsPromise> { {% endif %} #[allow(unused_imports)] -use neon::{prelude::*, types::buffer::TypedArray}; +use neon::{prelude::*, types::{buffer::TypedArray, JsBigInt}}; {# Enum #} {% for enum in api.enums %} diff --git a/bindings/generator/templates/binding_web_meths.rs.j2 b/bindings/generator/templates/binding_web_meths.rs.j2 index a2d9d7a6e18..6737a4ef248 100644 --- a/bindings/generator/templates/binding_web_meths.rs.j2 +++ b/bindings/generator/templates/binding_web_meths.rs.j2 @@ -286,11 +286,7 @@ if {{ js_val }}.is_null() { } {%- elif type.kind == "i64_based" -%} { - let v = {{ js_val }}.dyn_into::<Number>().map_err(|_| TypeError::new("Not a number"))?.value_of(); - if v < (i64::MIN as f64) || (i64::MAX as f64) < v { - return Err(JsValue::from(TypeError::new("Not an i64 number"))); - } - let v = v as i64; + let v = i64::try_from({{ js_val }}).map_err(|_| TypeError::new("Not a BigInt representing an i64 number"))?; {% if type.custom_from_rs_i64 -%} let custom_from_rs_i64 = {{ type.custom_from_rs_i64 }}; match custom_from_rs_i64(v) { @@ -303,11 +299,7 @@ if {{ js_val }}.is_null() { } {%- elif type.kind == "u64_based" -%} { - let v = {{ js_val }}.dyn_into::<Number>().map_err(|_| TypeError::new("Not a number"))?.value_of(); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - return Err(JsValue::from(TypeError::new("Not an u64 number"))); - } - let v = v as u64; + let v = u64::try_from({{ js_val }}).map_err(|_| TypeError::new("Not a BigInt representing an u64 number"))?; {% if type.custom_from_rs_u64 -%} let custom_from_rs_u64 = {{ type.custom_from_rs_u64 }}; match custom_from_rs_u64(v) { @@ -501,7 +493,7 @@ JsValue::from({{ rs_value }}) {%- elif type.kind == "i64_based" -%} {%- if type.custom_to_rs_i64 %} { - let custom_to_rs_i64 = {{ type.custom_to_rs_i32 }}; + let custom_to_rs_i64 = {{ type.custom_to_rs_i64 }}; let v = match custom_to_rs_i64({{ rs_value }}) { Ok(ok) => ok, Err(err) => return Err(JsValue::from(TypeError::new(err.as_ref()))), @@ -514,7 +506,7 @@ JsValue::from({{ rs_value }}) {%- elif type.kind == "u64_based" -%} {%- if type.custom_to_rs_u64 %} { - let custom_to_rs_u64 = {{ type.custom_to_rs_i32 }}; + let custom_to_rs_u64 = {{ type.custom_to_rs_u64 }}; let v = match custom_to_rs_u64({{ rs_value }}) { Ok(ok) => ok, Err(err) => return Err(JsValue::from(TypeError::new(err.as_ref()))), diff --git a/bindings/generator/templates/client_plugin_definitions.ts.j2 b/bindings/generator/templates/client_plugin_definitions.ts.j2 index db8816c83c2..1025d027b19 100644 --- a/bindings/generator/templates/client_plugin_definitions.ts.j2 +++ b/bindings/generator/templates/client_plugin_definitions.ts.j2 @@ -82,13 +82,20 @@ export type {{ type.name }} = Uint8Array {% endif %} {% endfor %} {# Number-based types #} -{% for type in api.u8_based_types + api.i32_based_types + api.u32_based_types + api.i64_based_types + api.u64_based_types + api.f64_based_types %} +{% for type in api.u8_based_types + api.i32_based_types + api.u32_based_types + api.f64_based_types %} {% if type.custom_ts_type_declaration %} {{ type.custom_ts_type_declaration }} {% else %} export type {{ type.name }} = number {% endif %} {% endfor %} +{% for type in api.i64_based_types + api.u64_based_types %} +{% if type.custom_ts_type_declaration %} +{{ type.custom_ts_type_declaration }} +{% else %} +export type {{ type.name }} = bigint +{% endif %} +{% endfor %} {# Structures #} {% for struct in api.structs %} From d1bd926e93364cced420fffa40071281f2e587f6 Mon Sep 17 00:00:00 2001 From: Emmanuel Leblond <emmanuel.leblond@gmail.com> Date: Mon, 20 Jan 2025 12:21:35 +0100 Subject: [PATCH 4/5] Re-generate electron&web bindings --- bindings/electron/src/meths.rs | 189 +++++++++----------- bindings/web/src/meths.rs | 90 ++-------- client/src/plugins/libparsec/definitions.ts | 8 +- 3 files changed, 102 insertions(+), 185 deletions(-) diff --git a/bindings/electron/src/meths.rs b/bindings/electron/src/meths.rs index eb91911a97c..5c53ec5eca9 100644 --- a/bindings/electron/src/meths.rs +++ b/bindings/electron/src/meths.rs @@ -5,7 +5,10 @@ */ #[allow(unused_imports)] -use neon::{prelude::*, types::buffer::TypedArray}; +use neon::{ + prelude::*, + types::{buffer::TypedArray, JsBigInt}, +}; // CancelledGreetingAttemptReason @@ -1433,13 +1436,11 @@ fn struct_file_stat_js_to_rs<'a>( js_val.value(cx) }; let size = { - let js_val: Handle<JsNumber> = obj.get(cx, "size")?; + let js_val: Handle<JsBigInt> = obj.get(cx, "size")?; { - let v = js_val.value(cx); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - cx.throw_type_error("Not an u64 number")? - } - let v = v as u64; + let v = js_val + .to_u64(cx) + .or_else(|_| cx.throw_type_error("Not an u64 number"))?; v } }; @@ -1496,7 +1497,7 @@ fn struct_file_stat_rs_to_js<'a>( js_obj.set(cx, "isPlaceholder", js_is_placeholder)?; let js_need_sync = JsBoolean::new(cx, rs_obj.need_sync); js_obj.set(cx, "needSync", js_need_sync)?; - let js_size = JsNumber::new(cx, rs_obj.size as f64); + let js_size = JsBigInt::from_u64(cx, rs_obj.size); js_obj.set(cx, "size", js_size)?; Ok(js_obj) } @@ -3642,13 +3643,11 @@ fn struct_workspace_history_file_stat_js_to_rs<'a>( } }; let size = { - let js_val: Handle<JsNumber> = obj.get(cx, "size")?; + let js_val: Handle<JsBigInt> = obj.get(cx, "size")?; { - let v = js_val.value(cx); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - cx.throw_type_error("Not an u64 number")? - } - let v = v as u64; + let v = js_val + .to_u64(cx) + .or_else(|_| cx.throw_type_error("Not an u64 number"))?; v } }; @@ -3699,7 +3698,7 @@ fn struct_workspace_history_file_stat_rs_to_js<'a>( js_obj.set(cx, "updated", js_updated)?; let js_version = JsNumber::new(cx, rs_obj.version as f64); js_obj.set(cx, "version", js_version)?; - let js_size = JsNumber::new(cx, rs_obj.size as f64); + let js_size = JsBigInt::from_u64(cx, rs_obj.size); js_obj.set(cx, "size", js_size)?; Ok(js_obj) } @@ -3870,13 +3869,11 @@ fn variant_active_users_limit_js_to_rs<'a>( match tag.as_str() { "ActiveUsersLimitLimitedTo" => { let x0 = { - let js_val: Handle<JsNumber> = obj.get(cx, "x0")?; + let js_val: Handle<JsBigInt> = obj.get(cx, "x0")?; { - let v = js_val.value(cx); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - cx.throw_type_error("Not an u64 number")? - } - let v = v as u64; + let v = js_val + .to_u64(cx) + .or_else(|_| cx.throw_type_error("Not an u64 number"))?; v } }; @@ -3897,7 +3894,7 @@ fn variant_active_users_limit_rs_to_js<'a>( libparsec::ActiveUsersLimit::LimitedTo(x0, ..) => { let js_tag = JsString::try_new(cx, "LimitedTo").or_throw(cx)?; js_obj.set(cx, "tag", js_tag)?; - let js_x0 = JsNumber::new(cx, x0 as f64); + let js_x0 = JsBigInt::from_u64(cx, x0); js_obj.set(cx, "x0", js_x0)?; } libparsec::ActiveUsersLimit::NoLimit { .. } => { @@ -5021,35 +5018,29 @@ fn variant_client_event_js_to_rs<'a>( } }; let blocks = { - let js_val: Handle<JsNumber> = obj.get(cx, "blocks")?; + let js_val: Handle<JsBigInt> = obj.get(cx, "blocks")?; { - let v = js_val.value(cx); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - cx.throw_type_error("Not an u64 number")? - } - let v = v as u64; + let v = js_val + .to_u64(cx) + .or_else(|_| cx.throw_type_error("Not an u64 number"))?; v } }; let block_index = { - let js_val: Handle<JsNumber> = obj.get(cx, "blockIndex")?; + let js_val: Handle<JsBigInt> = obj.get(cx, "blockIndex")?; { - let v = js_val.value(cx); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - cx.throw_type_error("Not an u64 number")? - } - let v = v as u64; + let v = js_val + .to_u64(cx) + .or_else(|_| cx.throw_type_error("Not an u64 number"))?; v } }; let blocksize = { - let js_val: Handle<JsNumber> = obj.get(cx, "blocksize")?; + let js_val: Handle<JsBigInt> = obj.get(cx, "blocksize")?; { - let v = js_val.value(cx); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - cx.throw_type_error("Not an u64 number")? - } - let v = v as u64; + let v = js_val + .to_u64(cx) + .or_else(|_| cx.throw_type_error("Not an u64 number"))?; v } }; @@ -5433,11 +5424,11 @@ fn variant_client_event_rs_to_js<'a>( }) .or_throw(cx)?; js_obj.set(cx, "entryId", js_entry_id)?; - let js_blocks = JsNumber::new(cx, blocks as f64); + let js_blocks = JsBigInt::from_u64(cx, blocks); js_obj.set(cx, "blocks", js_blocks)?; - let js_block_index = JsNumber::new(cx, block_index as f64); + let js_block_index = JsBigInt::from_u64(cx, block_index); js_obj.set(cx, "blockIndex", js_block_index)?; - let js_blocksize = JsNumber::new(cx, blocksize as f64); + let js_blocksize = JsBigInt::from_u64(cx, blocksize); js_obj.set(cx, "blocksize", js_blocksize)?; } libparsec::ClientEvent::WorkspaceOpsOutboundSyncStarted { @@ -6850,13 +6841,11 @@ fn variant_entry_stat_js_to_rs<'a>( js_val.value(cx) }; let size = { - let js_val: Handle<JsNumber> = obj.get(cx, "size")?; + let js_val: Handle<JsBigInt> = obj.get(cx, "size")?; { - let v = js_val.value(cx); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - cx.throw_type_error("Not an u64 number")? - } - let v = v as u64; + let v = js_val + .to_u64(cx) + .or_else(|_| cx.throw_type_error("Not an u64 number"))?; v } }; @@ -7061,7 +7050,7 @@ fn variant_entry_stat_rs_to_js<'a>( js_obj.set(cx, "isPlaceholder", js_is_placeholder)?; let js_need_sync = JsBoolean::new(cx, need_sync); js_obj.set(cx, "needSync", js_need_sync)?; - let js_size = JsNumber::new(cx, size as f64); + let js_size = JsBigInt::from_u64(cx, size); js_obj.set(cx, "size", js_size)?; } libparsec::EntryStat::Folder { @@ -9503,13 +9492,11 @@ fn variant_parsed_parsec_addr_js_to_rs<'a>( } }; let key_index = { - let js_val: Handle<JsNumber> = obj.get(cx, "keyIndex")?; + let js_val: Handle<JsBigInt> = obj.get(cx, "keyIndex")?; { - let v = js_val.value(cx); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - cx.throw_type_error("Not an u64 number")? - } - let v = v as u64; + let v = js_val + .to_u64(cx) + .or_else(|_| cx.throw_type_error("Not an u64 number"))?; v } }; @@ -9732,7 +9719,7 @@ fn variant_parsed_parsec_addr_rs_to_js<'a>( }) .or_throw(cx)?; js_obj.set(cx, "workspaceId", js_workspace_id)?; - let js_key_index = JsNumber::new(cx, key_index as f64); + let js_key_index = JsBigInt::from_u64(cx, key_index); js_obj.set(cx, "keyIndex", js_key_index)?; let js_encrypted_path = { let mut js_buff = JsArrayBuffer::new(cx, encrypted_path.len())?; @@ -12670,13 +12657,11 @@ fn variant_workspace_history_entry_stat_js_to_rs<'a>( } }; let size = { - let js_val: Handle<JsNumber> = obj.get(cx, "size")?; + let js_val: Handle<JsBigInt> = obj.get(cx, "size")?; { - let v = js_val.value(cx); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - cx.throw_type_error("Not an u64 number")? - } - let v = v as u64; + let v = js_val + .to_u64(cx) + .or_else(|_| cx.throw_type_error("Not an u64 number"))?; v } }; @@ -12825,7 +12810,7 @@ fn variant_workspace_history_entry_stat_rs_to_js<'a>( js_obj.set(cx, "updated", js_updated)?; let js_version = JsNumber::new(cx, version as f64); js_obj.set(cx, "version", js_version)?; - let js_size = JsNumber::new(cx, size as f64); + let js_size = JsBigInt::from_u64(cx, size); js_obj.set(cx, "size", js_size)?; } libparsec::WorkspaceHistoryEntryStat::Folder { @@ -20342,24 +20327,20 @@ fn workspace_fd_read(mut cx: FunctionContext) -> JsResult<JsPromise> { } }; let offset = { - let js_val = cx.argument::<JsNumber>(2)?; + let js_val = cx.argument::<JsBigInt>(2)?; { - let v = js_val.value(&mut cx); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - cx.throw_type_error("Not an u64 number")? - } - let v = v as u64; + let v = js_val + .to_u64(&mut cx) + .or_else(|_| cx.throw_type_error("Not an u64 number"))?; v } }; let size = { - let js_val = cx.argument::<JsNumber>(3)?; + let js_val = cx.argument::<JsBigInt>(3)?; { - let v = js_val.value(&mut cx); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - cx.throw_type_error("Not an u64 number")? - } - let v = v as u64; + let v = js_val + .to_u64(&mut cx) + .or_else(|_| cx.throw_type_error("Not an u64 number"))?; v } }; @@ -20437,13 +20418,11 @@ fn workspace_fd_resize(mut cx: FunctionContext) -> JsResult<JsPromise> { } }; let length = { - let js_val = cx.argument::<JsNumber>(2)?; + let js_val = cx.argument::<JsBigInt>(2)?; { - let v = js_val.value(&mut cx); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - cx.throw_type_error("Not an u64 number")? - } - let v = v as u64; + let v = js_val + .to_u64(&mut cx) + .or_else(|_| cx.throw_type_error("Not an u64 number"))?; v } }; @@ -20588,13 +20567,11 @@ fn workspace_fd_write(mut cx: FunctionContext) -> JsResult<JsPromise> { } }; let offset = { - let js_val = cx.argument::<JsNumber>(2)?; + let js_val = cx.argument::<JsBigInt>(2)?; { - let v = js_val.value(&mut cx); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - cx.throw_type_error("Not an u64 number")? - } - let v = v as u64; + let v = js_val + .to_u64(&mut cx) + .or_else(|_| cx.throw_type_error("Not an u64 number"))?; v } }; @@ -20618,7 +20595,7 @@ fn workspace_fd_write(mut cx: FunctionContext) -> JsResult<JsPromise> { let js_obj = JsObject::new(&mut cx); let js_tag = JsBoolean::new(&mut cx, true); js_obj.set(&mut cx, "ok", js_tag)?; - let js_value = JsNumber::new(&mut cx, ok as f64); + let js_value = JsBigInt::from_u64(&mut cx, ok); js_obj.set(&mut cx, "value", js_value)?; js_obj } @@ -20669,13 +20646,11 @@ fn workspace_fd_write_constrained_io(mut cx: FunctionContext) -> JsResult<JsProm } }; let offset = { - let js_val = cx.argument::<JsNumber>(2)?; + let js_val = cx.argument::<JsBigInt>(2)?; { - let v = js_val.value(&mut cx); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - cx.throw_type_error("Not an u64 number")? - } - let v = v as u64; + let v = js_val + .to_u64(&mut cx) + .or_else(|_| cx.throw_type_error("Not an u64 number"))?; v } }; @@ -20700,7 +20675,7 @@ fn workspace_fd_write_constrained_io(mut cx: FunctionContext) -> JsResult<JsProm let js_obj = JsObject::new(&mut cx); let js_tag = JsBoolean::new(&mut cx, true); js_obj.set(&mut cx, "ok", js_tag)?; - let js_value = JsNumber::new(&mut cx, ok as f64); + let js_value = JsBigInt::from_u64(&mut cx, ok); js_obj.set(&mut cx, "value", js_value)?; js_obj } @@ -20770,7 +20745,7 @@ fn workspace_fd_write_start_eof(mut cx: FunctionContext) -> JsResult<JsPromise> let js_obj = JsObject::new(&mut cx); let js_tag = JsBoolean::new(&mut cx, true); js_obj.set(&mut cx, "ok", js_tag)?; - let js_value = JsNumber::new(&mut cx, ok as f64); + let js_value = JsBigInt::from_u64(&mut cx, ok); js_obj.set(&mut cx, "value", js_value)?; js_obj } @@ -22033,24 +22008,20 @@ fn workspace_history_fd_read(mut cx: FunctionContext) -> JsResult<JsPromise> { } }; let offset = { - let js_val = cx.argument::<JsNumber>(2)?; + let js_val = cx.argument::<JsBigInt>(2)?; { - let v = js_val.value(&mut cx); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - cx.throw_type_error("Not an u64 number")? - } - let v = v as u64; + let v = js_val + .to_u64(&mut cx) + .or_else(|_| cx.throw_type_error("Not an u64 number"))?; v } }; let size = { - let js_val = cx.argument::<JsNumber>(3)?; + let js_val = cx.argument::<JsBigInt>(3)?; { - let v = js_val.value(&mut cx); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - cx.throw_type_error("Not an u64 number")? - } - let v = v as u64; + let v = js_val + .to_u64(&mut cx) + .or_else(|_| cx.throw_type_error("Not an u64 number"))?; v } }; diff --git a/bindings/web/src/meths.rs b/bindings/web/src/meths.rs index e8949057a60..698445e0548 100644 --- a/bindings/web/src/meths.rs +++ b/bindings/web/src/meths.rs @@ -1550,14 +1550,8 @@ fn struct_file_stat_js_to_rs(obj: JsValue) -> Result<libparsec::FileStat, JsValu let size = { let js_val = Reflect::get(&obj, &"size".into())?; { - let v = js_val - .dyn_into::<Number>() - .map_err(|_| TypeError::new("Not a number"))? - .value_of(); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - return Err(JsValue::from(TypeError::new("Not an u64 number"))); - } - let v = v as u64; + let v = u64::try_from(js_val) + .map_err(|_| TypeError::new("Not a BigInt representing an u64 number"))?; v } }; @@ -3898,14 +3892,8 @@ fn struct_workspace_history_file_stat_js_to_rs( let size = { let js_val = Reflect::get(&obj, &"size".into())?; { - let v = js_val - .dyn_into::<Number>() - .map_err(|_| TypeError::new("Not a number"))? - .value_of(); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - return Err(JsValue::from(TypeError::new("Not an u64 number"))); - } - let v = v as u64; + let v = u64::try_from(js_val) + .map_err(|_| TypeError::new("Not a BigInt representing an u64 number"))?; v } }; @@ -4149,14 +4137,8 @@ fn variant_active_users_limit_js_to_rs( let x1 = { let js_val = Reflect::get(&obj, &"x1".into())?; { - let v = js_val - .dyn_into::<Number>() - .map_err(|_| TypeError::new("Not a number"))? - .value_of(); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - return Err(JsValue::from(TypeError::new("Not an u64 number"))); - } - let v = v as u64; + let v = u64::try_from(js_val) + .map_err(|_| TypeError::new("Not a BigInt representing an u64 number"))?; v } }; @@ -5490,42 +5472,24 @@ fn variant_client_event_js_to_rs(obj: JsValue) -> Result<libparsec::ClientEvent, let blocks = { let js_val = Reflect::get(&obj, &"blocks".into())?; { - let v = js_val - .dyn_into::<Number>() - .map_err(|_| TypeError::new("Not a number"))? - .value_of(); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - return Err(JsValue::from(TypeError::new("Not an u64 number"))); - } - let v = v as u64; + let v = u64::try_from(js_val) + .map_err(|_| TypeError::new("Not a BigInt representing an u64 number"))?; v } }; let block_index = { let js_val = Reflect::get(&obj, &"blockIndex".into())?; { - let v = js_val - .dyn_into::<Number>() - .map_err(|_| TypeError::new("Not a number"))? - .value_of(); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - return Err(JsValue::from(TypeError::new("Not an u64 number"))); - } - let v = v as u64; + let v = u64::try_from(js_val) + .map_err(|_| TypeError::new("Not a BigInt representing an u64 number"))?; v } }; let blocksize = { let js_val = Reflect::get(&obj, &"blocksize".into())?; { - let v = js_val - .dyn_into::<Number>() - .map_err(|_| TypeError::new("Not a number"))? - .value_of(); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - return Err(JsValue::from(TypeError::new("Not an u64 number"))); - } - let v = v as u64; + let v = u64::try_from(js_val) + .map_err(|_| TypeError::new("Not a BigInt representing an u64 number"))?; v } }; @@ -7579,14 +7543,8 @@ fn variant_entry_stat_js_to_rs(obj: JsValue) -> Result<libparsec::EntryStat, JsV let size = { let js_val = Reflect::get(&obj, &"size".into())?; { - let v = js_val - .dyn_into::<Number>() - .map_err(|_| TypeError::new("Not a number"))? - .value_of(); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - return Err(JsValue::from(TypeError::new("Not an u64 number"))); - } - let v = v as u64; + let v = u64::try_from(js_val) + .map_err(|_| TypeError::new("Not a BigInt representing an u64 number"))?; v } }; @@ -10558,14 +10516,8 @@ fn variant_parsed_parsec_addr_js_to_rs( let key_index = { let js_val = Reflect::get(&obj, &"keyIndex".into())?; { - let v = js_val - .dyn_into::<Number>() - .map_err(|_| TypeError::new("Not a number"))? - .value_of(); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - return Err(JsValue::from(TypeError::new("Not an u64 number"))); - } - let v = v as u64; + let v = u64::try_from(js_val) + .map_err(|_| TypeError::new("Not a BigInt representing an u64 number"))?; v } }; @@ -14085,14 +14037,8 @@ fn variant_workspace_history_entry_stat_js_to_rs( let size = { let js_val = Reflect::get(&obj, &"size".into())?; { - let v = js_val - .dyn_into::<Number>() - .map_err(|_| TypeError::new("Not a number"))? - .value_of(); - if v < (u64::MIN as f64) || (u64::MAX as f64) < v { - return Err(JsValue::from(TypeError::new("Not an u64 number"))); - } - let v = v as u64; + let v = u64::try_from(js_val) + .map_err(|_| TypeError::new("Not a BigInt representing an u64 number"))?; v } }; diff --git a/client/src/plugins/libparsec/definitions.ts b/client/src/plugins/libparsec/definitions.ts index 0cc83db63e0..969de264b13 100644 --- a/client/src/plugins/libparsec/definitions.ts +++ b/client/src/plugins/libparsec/definitions.ts @@ -103,11 +103,11 @@ export type FileDescriptor = number export type Handle = number export type U32 = number export type VersionInt = number -export type I64 = number -export type IndexInt = number -export type SizeInt = number -export type U64 = number export type { DateTime } from 'luxon'; import type { DateTime } from 'luxon'; +export type I64 = bigint +export type IndexInt = bigint +export type SizeInt = bigint +export type U64 = bigint export interface AvailableDevice { keyFilePath: Path From 0262eb82bff168fab7a05ab46dff427e4b2ec43a Mon Sep 17 00:00:00 2001 From: Maxime GRANDCOLAS <maxime.grandcolas@scille.fr> Date: Fri, 17 Jan 2025 17:16:24 +0100 Subject: [PATCH 5/5] [MS] Update GUI to use bindings in web mode --- client/.env.development | 2 + client/README.md | 20 +- client/playwright.config.ts | 15 + client/src/common/file.ts | 4 +- client/src/main.ts | 33 +- client/src/parsec/claim_device.ts | 226 +++----- client/src/parsec/claim_user.ts | 258 +++------ client/src/parsec/device.ts | 123 +---- client/src/parsec/environment.ts | 7 - client/src/parsec/file.ts | 299 +++-------- client/src/parsec/greet_device.ts | 162 ++---- client/src/parsec/greet_user.ts | 171 ++---- client/src/parsec/history.ts | 228 ++------ client/src/parsec/invitation.ts | 97 +--- client/src/parsec/login.ts | 159 +----- client/src/parsec/organization.ts | 147 ++--- client/src/parsec/terms_of_service.ts | 21 +- client/src/parsec/user.ts | 132 +---- client/src/parsec/utils.ts | 7 + client/src/parsec/workspace.ts | 240 ++------- client/src/router/types.ts | 124 ++--- client/src/services/fileOperationManager.ts | 10 +- client/src/services/hotkeyManager.ts | 4 +- client/src/services/informationManager.ts | 4 +- client/src/services/injectionProvider.ts | 4 +- client/src/services/storageManager.ts | 5 + client/src/views/devices/GreetDeviceModal.vue | 2 +- .../home/DeviceJoinOrganizationModal.vue | 2 +- client/src/views/layouts/ConnectedLayout.vue | 67 +-- client/src/views/layouts/DevLayout.vue | 124 +++++ client/src/views/layouts/LoadingLayout.vue | 6 +- .../creation/CreateOrganizationSaas.vue | 1 + client/src/views/users/GreetUserModal.vue | 20 +- client/src/views/users/UsersPage.vue | 4 +- client/src/views/viewers/FileViewer.vue | 4 +- client/src/views/viewers/PdfViewer.vue | 4 +- .../src/views/workspaces/WorkspacesPage.vue | 8 +- .../component/specs/testFileCard.spec.ts | 2 +- .../component/specs/testFileListItem.spec.ts | 2 +- client/tests/e2e/data/imports/audio.mp3 | Bin 0 -> 41866 bytes client/tests/e2e/data/imports/code.py | 31 ++ client/tests/e2e/data/imports/document.docx | Bin 0 -> 15580 bytes client/tests/e2e/data/imports/image.png | Bin 0 -> 6335 bytes client/tests/e2e/data/imports/pdfDocument.pdf | Bin 0 -> 78731 bytes .../tests/e2e/data/imports/spreadsheet.xlsx | Bin 0 -> 6139 bytes client/tests/e2e/data/imports/text.txt | 1 + client/tests/e2e/data/imports/video.mp4 | Bin 0 -> 176994 bytes client/tests/e2e/helpers/assertions.ts | 4 +- client/tests/e2e/helpers/bms.ts | 98 ++-- client/tests/e2e/helpers/data.ts | 54 +- client/tests/e2e/helpers/fixtures.ts | 136 +++-- client/tests/e2e/helpers/utils.ts | 51 +- .../e2e/specs/client_area_dashboard.spec.ts | 8 +- .../specs/client_area_invoices_page.spec.ts | 4 +- .../tests/e2e/specs/client_area_login.spec.ts | 16 +- .../specs/create_organization_custom.spec.ts | 42 +- .../specs/create_organization_saas.spec.ts | 35 +- .../specs/create_organization_trial.spec.ts | 16 +- client/tests/e2e/specs/device_greet.spec.ts | 477 +++++++++++++--- .../specs/device_join_organization.spec.ts | 83 --- .../e2e/specs/document_context_menu.spec.ts | 20 +- client/tests/e2e/specs/home_page.spec.ts | 4 +- .../e2e/specs/invitations_popover.spec.ts | 26 +- .../tests/e2e/specs/my_profile_page.spec.ts | 2 +- .../specs/organization_information.spec.ts | 8 +- .../specs/organization_switch_popover.spec.ts | 2 +- .../tests/e2e/specs/profile_popover.spec.ts | 3 +- client/tests/e2e/specs/sidebar.spec.ts | 9 +- client/tests/e2e/specs/user_greet.spec.ts | 507 ++++++++++++++---- client/tests/e2e/specs/user_join.spec.ts | 133 ----- .../e2e/specs/workspaces_actions.spec.ts | 125 +++-- .../tests/e2e/specs/workspaces_list.spec.ts | 158 +++--- 72 files changed, 2131 insertions(+), 2670 deletions(-) create mode 100644 client/src/parsec/utils.ts create mode 100644 client/src/views/layouts/DevLayout.vue create mode 100644 client/tests/e2e/data/imports/audio.mp3 create mode 100644 client/tests/e2e/data/imports/code.py create mode 100644 client/tests/e2e/data/imports/document.docx create mode 100644 client/tests/e2e/data/imports/image.png create mode 100644 client/tests/e2e/data/imports/pdfDocument.pdf create mode 100644 client/tests/e2e/data/imports/spreadsheet.xlsx create mode 100644 client/tests/e2e/data/imports/text.txt create mode 100644 client/tests/e2e/data/imports/video.mp4 delete mode 100644 client/tests/e2e/specs/device_join_organization.spec.ts delete mode 100644 client/tests/e2e/specs/user_join.spec.ts diff --git a/client/.env.development b/client/.env.development index d83c7e6b03c..1b5028a9437 100644 --- a/client/.env.development +++ b/client/.env.development @@ -7,3 +7,5 @@ PARSEC_APP_BMS_USE_MOCK="false" PARSEC_APP_BMS_MOCKED_FUNCTIONS="" PARSEC_APP_BMS_FAIL_FUNCTIONS="" PARSEC_APP_DISABLE_SENTRY=true +PARSEC_APP_CREATE_DEFAULT_WORKSPACES="true" +PARSEC_APP_CLEAR_CACHE="true" diff --git a/client/README.md b/client/README.md index 1c848b161a7..3a7df3b002a 100644 --- a/client/README.md +++ b/client/README.md @@ -119,12 +119,14 @@ ionic cap add ios ## Variables -| Name | Type | Description | Remark | -| ----------------------------------- | ------------------------- | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | -| `PARSEC_APP_DEV_BMS_CREDENTIALS` | `<email>:<password>` | Used as default login credentials for the BMS | Only for development purposes! Avoid using `:` in your password as it will mess up the parsing. | -| `PARSEC_APP_BMS_USE_MOCK` | `boolean` | Used to mock calls to the BMS | Only for development purposes! | -| `PARSEC_APP_BMS_MOCKED_FUNCTIONS ` | `function1;function2;...` | Comma-separated list of functions from the BMS API to mock | Only for development purposes! | -| `PARSEC_APP_BMS_FAIL_FUNCTIONS ` | `function1;function2;...` | Comma-separated list of functions from the BMS API that should fail if mocked | Only for development purposes! | -| `PARSEC_APP_DISABLE_STRIPE` | `boolean` | Disable Stripe and hide the customer area | | -| `PARSEC_APP_DISABLE_SENTRY` | `boolean` | Disable Sentry | | -| `PARSEC_APP_BMS_MOCK_WAIT_DURATION` | `number` | How much time mocked BMS functions should take, to simulate network and server slowness | Only for development purposes! | +| Name | Type | Description | Remark | +| -------------------------------------- | ------------------------- | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | +| `PARSEC_APP_DEV_BMS_CREDENTIALS` | `<email>:<password>` | Used as default login credentials for the BMS | Only for development purposes! Avoid using `:` in your password as it will mess up the parsing. | +| `PARSEC_APP_BMS_USE_MOCK` | `boolean` | Used to mock calls to the BMS | Only for development purposes! | +| `PARSEC_APP_BMS_MOCKED_FUNCTIONS ` | `function1;function2;...` | Comma-separated list of functions from the BMS API to mock | Only for development purposes! | +| `PARSEC_APP_BMS_FAIL_FUNCTIONS ` | `function1;function2;...` | Comma-separated list of functions from the BMS API that should fail if mocked | Only for development purposes! | +| `PARSEC_APP_DISABLE_STRIPE` | `boolean` | Disable Stripe and hide the customer area | | +| `PARSEC_APP_DISABLE_SENTRY` | `boolean` | Disable Sentry | | +| `PARSEC_APP_BMS_MOCK_WAIT_DURATION` | `number` | How much time mocked BMS functions should take, to simulate network and server slowness | Only for development purposes! | +| `PARSEC_APP_CREATE_DEFAULT_WORKSPACES` | `boolean` | Create default workspaces when initializing the app | Only for development purposes! | +| `PARSEC_APP_CLEAR_CACHE` | `boolean` | Clear the cache | Only for development purposes! | diff --git a/client/playwright.config.ts b/client/playwright.config.ts index 99858c301af..35f69d7b618 100644 --- a/client/playwright.config.ts +++ b/client/playwright.config.ts @@ -37,6 +37,21 @@ export default defineConfig({ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'on-first-retry', }, + testIgnore: [ + '**/workspace_sharing.spec.ts', + '**/workspace_history.spec.ts', + '**/user_list.spec.ts', + '**/user_details.spec.ts', + '**/document_context_menu.spec.ts', + '**/file_import.spec.ts', + '**/file_details.spec.ts', + '**/file_viewers.spec.ts', + '**/file_viewers_document.spec.ts', + '**/file_viewers_pdf.spec.ts', + '**/documents_list.spec.ts', + '**/export_recovery_device.spec.ts', + '**/import_recovery_device.spec.ts', + ], /* Configure projects for major browsers */ projects: [ { diff --git a/client/src/common/file.ts b/client/src/common/file.ts index 34c2cb905b4..05884d0874b 100644 --- a/client/src/common/file.ts +++ b/client/src/common/file.ts @@ -75,7 +75,7 @@ function size(bytes: number, system: [number, string][]): Translatable { return { key: key, data: { size: formattedAmount } }; } -export function formatFileSize(bytesize: number): Translatable { +export function formatFileSize(bytesize: number | bigint): Translatable { const SYSTEM: [number, string][] = [ [Math.pow(1024, 0), 'common.filesize.bytes'], [Math.pow(1024, 1), 'common.filesize.kilobytes'], @@ -83,7 +83,7 @@ export function formatFileSize(bytesize: number): Translatable { [Math.pow(1024, 3), 'common.filesize.gigabytes'], [Math.pow(1024, 4), 'common.filesize.terabytes'], ]; - return size(bytesize, SYSTEM); + return size(Number(bytesize), SYSTEM); } /* File icons */ diff --git a/client/src/main.ts b/client/src/main.ts index 909ec9cf0c9..e936c03d957 100644 --- a/client/src/main.ts +++ b/client/src/main.ts @@ -23,7 +23,7 @@ import { availableDeviceMatchesServer } from '@/common/device'; import { bootstrapLinkValidator, claimLinkValidator, fileLinkValidator } from '@/common/validators'; import appEnUS from '@/locales/en-US.json'; import appFrFR from '@/locales/fr-FR.json'; -import { getLoggedInDevices, getOrganizationHandle, isElectron, listAvailableDevices, logout, needsMocks, parseFileLink } from '@/parsec'; +import { getLoggedInDevices, getOrganizationHandle, isElectron, listAvailableDevices, logout, parseFileLink } from '@/parsec'; import { getClientConfig } from '@/parsec/internals'; import { AvailableDevice, Platform, libparsec } from '@/plugins/libparsec'; import { Env } from '@/services/environment'; @@ -54,6 +54,13 @@ function preventRightClick(): void { }); } +function warnRefresh(): void { + window.addEventListener('beforeunload', async (event) => { + event.preventDefault(); + event.returnValue = true; + }); +} + async function setupApp(): Promise<void> { await storageManagerInstance.init(); const storageManager = storageManagerInstance.get(); @@ -162,20 +169,10 @@ async function setupApp(): Promise<void> { app.provide(ThemeManagerKey, themeManager); if ((await libparsec.getPlatform()) === Platform.Web) { - if (!needsMocks()) { - // Only called when the user has interacted with the page - window.addEventListener('beforeunload', async (event: BeforeUnloadEvent) => { - event.preventDefault(); - event.returnValue = true; - }); - - window.addEventListener('unload', async (_event: Event) => { - // Stop the imports and properly logout on close. - await cleanBeforeQuitting(injectionProvider); - }); - } else { - Sentry.disable(); - } + window.addEventListener('unload', async (_event: Event) => { + // Stop the imports and properly logout on close. + await cleanBeforeQuitting(injectionProvider); + }); } if (isElectron()) { @@ -289,6 +286,7 @@ async function setupApp(): Promise<void> { // - dev or prod where devices are fetched from the local storage // - tests with Playwright where the testbed instantiation is done by Playwright if ('TESTING' in window && window.TESTING) { + Sentry.disable(); // handle the testbed and provides the configPath window.nextStageHook = (): any => { return [libparsec, nextStage]; @@ -372,7 +370,10 @@ function setupMockElectronAPI(injectionProvider: InjectionProvider): void { console[level](`[MOCKED-ELECTRON-LOG] ${message}`); }, pageIsInitialized: (): void => { - window.isDev = (): boolean => needsMocks(); + window.isDev = (): boolean => Boolean(import.meta.env.PARSEC_APP_TESTBED_SERVER); + if (!window.isDev()) { + warnRefresh(); + } }, openConfigDir: (): void => { console.log('OpenConfigDir: Not available'); diff --git a/client/src/parsec/claim_device.ts b/client/src/parsec/claim_device.ts index 7581369fe37..37724caf82a 100644 --- a/client/src/parsec/claim_device.ts +++ b/client/src/parsec/claim_device.ts @@ -12,15 +12,13 @@ import { DeviceClaimInProgress1Info, DeviceClaimInProgress2Info, DeviceClaimInProgress3Info, - DeviceFileType, DeviceLabel, DeviceSaveStrategy, HumanHandle, Result, SASCode, } from '@/parsec'; -import { needsMocks } from '@/parsec/environment'; -import { DEFAULT_HANDLE, MOCK_WAITING_TIME, getClientConfig, wait } from '@/parsec/internals'; +import { getClientConfig } from '@/parsec/internals'; import { libparsec } from '@/plugins/libparsec'; import { DateTime } from 'luxon'; @@ -44,10 +42,10 @@ export class DeviceClaim { } async abort(): Promise<void> { - if (this.canceller !== null && !needsMocks()) { + if (this.canceller !== null) { await libparsec.cancel(this.canceller); } - if (this.handle !== null && !needsMocks()) { + if (this.handle !== null) { await libparsec.claimerGreeterAbortOperation(this.handle); } this.canceller = null; @@ -79,193 +77,97 @@ export class DeviceClaim { this._assertState(true, true); - if (!needsMocks()) { - const clientConfig = getClientConfig(); - const result = await libparsec.claimerRetrieveInfo(clientConfig, eventCallback, invitationLink); - if (result.ok) { - if (result.value.tag !== AnyClaimRetrievedInfoTag.Device) { - throw Error('Unexpected tag'); - } - this.handle = result.value.handle; - this.greeter = result.value.greeterHumanHandle; + const clientConfig = getClientConfig(); + const result = await libparsec.claimerRetrieveInfo(clientConfig, eventCallback, invitationLink); + if (result.ok) { + if (result.value.tag !== AnyClaimRetrievedInfoTag.Device) { + throw Error('Unexpected tag'); } - return result as Result<AnyClaimRetrievedInfoDevice, ClaimerRetrieveInfoError>; - } else { - await wait(MOCK_WAITING_TIME); - this.handle = DEFAULT_HANDLE; - this.greeter = { - email: 'gale@waterdeep.faerun', - // cspell:disable-next-line - label: 'Gale Dekarios', - }; - return { - ok: true, - value: { - tag: AnyClaimRetrievedInfoTag.Device, - handle: DEFAULT_HANDLE, - greeterUserId: '1234', - greeterHumanHandle: { - email: 'gale@waterdeep.faerun', - // cspell:disable-next-line - label: 'Gale Dekarios', - }, - }, - }; + this.handle = result.value.handle; + this.greeter = result.value.greeterHumanHandle; } + return result as Result<AnyClaimRetrievedInfoDevice, ClaimerRetrieveInfoError>; } async initialWaitHost(): Promise<Result<DeviceClaimInProgress1Info, ClaimInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const result = await libparsec.claimerDeviceInitialDoWaitPeer(this.canceller, this.handle!); - if (result.ok) { - this.SASCodeChoices = result.value.greeterSasChoices; - this.correctSASCode = result.value.greeterSas; - this.handle = result.value.handle; - } - this.canceller = null; - return result; - } else { - this.SASCodeChoices = ['5MNO', '6PQR', '7STU', '8VWX']; - this.correctSASCode = '7STU'; - return { - ok: true, - value: { - handle: DEFAULT_HANDLE, - greeterUserId: '1234', - greeterHumanHandle: { - email: 'gale@waterdeep.faerun', - // cspell:disable-next-line - label: 'Gale Dekarios', - }, - greeterSas: this.correctSASCode, - greeterSasChoices: this.SASCodeChoices, - }, - }; + + this.canceller = await libparsec.newCanceller(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const result = await libparsec.claimerDeviceInitialDoWaitPeer(this.canceller, this.handle!); + if (result.ok) { + this.SASCodeChoices = result.value.greeterSasChoices; + this.correctSASCode = result.value.greeterSas; + this.handle = result.value.handle; } + this.canceller = null; + return result; } async denyTrust(): Promise<Result<null, ClaimInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const result = await libparsec.claimerDeviceInProgress1DoDenyTrust(this.canceller, this.handle!); - this.handle = null; - this.canceller = null; - return result; - } else { - return { ok: true, value: null }; - } + this.canceller = await libparsec.newCanceller(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const result = await libparsec.claimerDeviceInProgress1DoDenyTrust(this.canceller, this.handle!); + this.handle = null; + this.canceller = null; + return result; } async signifyTrust(): Promise<Result<DeviceClaimInProgress2Info, ClaimInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const result = await libparsec.claimerDeviceInProgress1DoSignifyTrust(this.canceller, this.handle!); - if (result.ok) { - this.guestSASCode = result.value.claimerSas; - this.handle = result.value.handle; - } - this.canceller = null; - return result; - } else { - this.guestSASCode = '1337'; - return { - ok: true, - value: { - handle: DEFAULT_HANDLE, - claimerSas: '1337', - }, - }; + this.canceller = await libparsec.newCanceller(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const result = await libparsec.claimerDeviceInProgress1DoSignifyTrust(this.canceller, this.handle!); + if (result.ok) { + this.guestSASCode = result.value.claimerSas; + this.handle = result.value.handle; } + this.canceller = null; + return result; } async waitHostTrust(): Promise<Result<DeviceClaimInProgress3Info, ClaimInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const result = await libparsec.claimerDeviceInProgress2DoWaitPeerTrust(this.canceller, this.handle!); - this.canceller = null; - if (result.ok) { - this.handle = result.value.handle; - } - return result; - } else { - await wait(MOCK_WAITING_TIME); - return { - ok: true, - value: { - handle: DEFAULT_HANDLE, - }, - }; + this.canceller = await libparsec.newCanceller(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const result = await libparsec.claimerDeviceInProgress2DoWaitPeerTrust(this.canceller, this.handle!); + this.canceller = null; + if (result.ok) { + this.handle = result.value.handle; } + return result; } async doClaim(deviceLabel: DeviceLabel): Promise<Result<DeviceClaimFinalizeInfo, ClaimInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - const result = await libparsec.claimerDeviceInProgress3DoClaim( - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this.canceller, - this.handle!, - deviceLabel, - ); - if (result.ok) { - this.handle = result.value.handle; - } - this.canceller = null; - return result; - } else { - await wait(MOCK_WAITING_TIME); - return { - ok: true, - value: { - handle: DEFAULT_HANDLE, - }, - }; + this.canceller = await libparsec.newCanceller(); + const result = await libparsec.claimerDeviceInProgress3DoClaim( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + this.canceller, + this.handle!, + deviceLabel, + ); + if (result.ok) { + this.handle = result.value.handle; } + this.canceller = null; + return result; } async finalize(saveStrategy: DeviceSaveStrategy): Promise<Result<AvailableDevice, ClaimInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - const result = await libparsec.claimerDeviceFinalizeSaveLocalDevice( - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this.handle!, - saveStrategy, - ); - if (result.ok) { - result.value.createdOn = DateTime.fromSeconds(result.value.createdOn as any as number); - result.value.protectedOn = DateTime.fromSeconds(result.value.protectedOn as any as number); - this.device = result.value; - } - this.handle = null; - return result; - } else { - this.handle = null; - this.device = { - keyFilePath: '/path', - serverUrl: 'https://parsec.invalid', - createdOn: DateTime.utc(), - protectedOn: DateTime.utc(), - organizationId: 'MyOrg', - userId: 'userid', - deviceId: 'deviceid', - humanHandle: { - label: 'A', - email: 'a@b.c', - }, - deviceLabel: 'a@b', - ty: DeviceFileType.Password, - }; - return { ok: true, value: this.device }; + const result = await libparsec.claimerDeviceFinalizeSaveLocalDevice( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + this.handle!, + saveStrategy, + ); + if (result.ok) { + result.value.createdOn = DateTime.fromSeconds(result.value.createdOn as any as number); + result.value.protectedOn = DateTime.fromSeconds(result.value.protectedOn as any as number); + this.device = result.value; } + this.handle = null; + return result; } } diff --git a/client/src/parsec/claim_user.ts b/client/src/parsec/claim_user.ts index e01ae739c9d..cd94fe9bdbe 100644 --- a/client/src/parsec/claim_user.ts +++ b/client/src/parsec/claim_user.ts @@ -8,7 +8,6 @@ import { ClaimerRetrieveInfoError, ClientEvent, ConnectionHandle, - DeviceFileType, DeviceSaveStrategy, HumanHandle, Result, @@ -17,11 +16,9 @@ import { UserClaimInProgress1Info, UserClaimInProgress2Info, UserClaimInProgress3Info, - UserOnlineStatus, } from '@/parsec'; -import { needsMocks } from '@/parsec/environment'; -import { DEFAULT_HANDLE, MOCK_WAITING_TIME, getClientConfig, wait } from '@/parsec/internals'; -import { InviteInfoInvitationCreatedByTag, libparsec } from '@/plugins/libparsec'; +import { getClientConfig } from '@/parsec/internals'; +import { libparsec } from '@/plugins/libparsec'; import { DateTime } from 'luxon'; export class UserClaim { @@ -46,10 +43,10 @@ export class UserClaim { } async abort(): Promise<void> { - if (this.canceller !== null && !needsMocks()) { + if (this.canceller !== null) { await libparsec.cancel(this.canceller); } - if (this.handle !== null && !needsMocks()) { + if (this.handle !== null) { await libparsec.claimerGreeterAbortOperation(this.handle); } this.canceller = null; @@ -82,221 +79,98 @@ export class UserClaim { this._assertState(true, true); - if (!needsMocks()) { - const clientConfig = getClientConfig(); - const result = await libparsec.claimerRetrieveInfo(clientConfig, eventCallback, invitationLink); - if (result.ok) { - if (result.value.tag !== AnyClaimRetrievedInfoTag.User) { - throw Error('Unexpected tag'); - } - this.handle = result.value.handle; - this.preferredGreeter = result.value.preferredGreeter?.humanHandle ?? null; + const clientConfig = getClientConfig(); + const result = await libparsec.claimerRetrieveInfo(clientConfig, eventCallback, invitationLink); + if (result.ok) { + if (result.value.tag !== AnyClaimRetrievedInfoTag.User) { + throw Error('Unexpected tag'); } - return result as Result<AnyClaimRetrievedInfoUser, ClaimerRetrieveInfoError>; - } else { - await wait(MOCK_WAITING_TIME); - this.handle = DEFAULT_HANDLE; - this.preferredGreeter = { - email: 'gale@waterdeep.faerun', - // cspell:disable-next-line - label: 'Gale Dekarios', - }; - return { - ok: true, - value: { - tag: AnyClaimRetrievedInfoTag.User, - handle: DEFAULT_HANDLE, - claimerEmail: 'shadowheart@swordcoast.faerun', - createdBy: { - tag: InviteInfoInvitationCreatedByTag.User, - userId: 'xxx', - humanHandle: { - email: 'gale@waterdeep.faerun', - // cspell:disable-next-line - label: 'Gale Dekarios', - }, - }, - administrators: [ - { - userId: '1234', - humanHandle: { - email: 'gale@waterdeep.faerun', - // cspell:disable-next-line - label: 'Gale Dekarios', - }, - lastGreetingAttemptJoinedOn: null, - onlineStatus: UserOnlineStatus.Unknown, - }, - ], - preferredGreeter: { - userId: '1234', - humanHandle: { - email: 'gale@waterdeep.faerun', - // cspell:disable-next-line - label: 'Gale Dekarios', - }, - lastGreetingAttemptJoinedOn: null, - onlineStatus: UserOnlineStatus.Unknown, - }, - }, - }; + this.handle = result.value.handle; + this.preferredGreeter = result.value.preferredGreeter?.humanHandle ?? null; } + return result as Result<AnyClaimRetrievedInfoUser, ClaimerRetrieveInfoError>; } async initialWaitAllAdministrators(): Promise<Result<UserClaimInProgress1Info, ClaimInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const result = await libparsec.claimerUserWaitAllPeers(this.canceller, this.handle!); - if (result.ok) { - this.SASCodeChoices = result.value.greeterSasChoices; - this.correctSASCode = result.value.greeterSas; - this.greeter = result.value.greeterHumanHandle; - this.handle = result.value.handle; - } - this.canceller = null; - return result; - } else { - this.SASCodeChoices = ['1ABC', '2DEF', '3GHI', '4JKL']; - this.correctSASCode = '2DEF'; - return { - ok: true, - value: { - handle: DEFAULT_HANDLE, - greeterUserId: '1234', - greeterHumanHandle: { - email: 'gale@waterdeep.faerun', - // cspell:disable-next-line - label: 'Gale Dekarios', - }, - greeterSas: '2DEF', - greeterSasChoices: ['1ABC', '2DEF', '3GHI', '4JKL'], - }, - }; + this.canceller = await libparsec.newCanceller(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const result = await libparsec.claimerUserWaitAllPeers(this.canceller, this.handle!); + if (result.ok) { + this.SASCodeChoices = result.value.greeterSasChoices; + this.correctSASCode = result.value.greeterSas; + this.greeter = result.value.greeterHumanHandle; + this.handle = result.value.handle; } + this.canceller = null; + return result; } async denyTrust(): Promise<Result<null, ClaimInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const result = await libparsec.claimerUserInProgress1DoDenyTrust(this.canceller, this.handle!); - this.handle = null; - this.canceller = null; - return result; - } else { - return { ok: true, value: null }; - } + this.canceller = await libparsec.newCanceller(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const result = await libparsec.claimerUserInProgress1DoDenyTrust(this.canceller, this.handle!); + this.handle = null; + this.canceller = null; + return result; } async signifyTrust(): Promise<Result<UserClaimInProgress2Info, ClaimInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const result = await libparsec.claimerUserInProgress1DoSignifyTrust(this.canceller, this.handle!); - if (result.ok) { - this.guestSASCode = result.value.claimerSas; - this.handle = result.value.handle; - } - this.canceller = null; - return result; - } else { - this.guestSASCode = '1337'; - return { - ok: true, - value: { - handle: DEFAULT_HANDLE, - claimerSas: '1337', - }, - }; + this.canceller = await libparsec.newCanceller(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const result = await libparsec.claimerUserInProgress1DoSignifyTrust(this.canceller, this.handle!); + if (result.ok) { + this.guestSASCode = result.value.claimerSas; + this.handle = result.value.handle; } + this.canceller = null; + return result; } async waitHostTrust(): Promise<Result<UserClaimInProgress3Info, ClaimInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const result = await libparsec.claimerUserInProgress2DoWaitPeerTrust(this.canceller, this.handle!); - this.canceller = null; - if (result.ok) { - this.handle = result.value.handle; - } - return result; - } else { - await wait(MOCK_WAITING_TIME); - return { - ok: true, - value: { - handle: DEFAULT_HANDLE, - }, - }; + this.canceller = await libparsec.newCanceller(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const result = await libparsec.claimerUserInProgress2DoWaitPeerTrust(this.canceller, this.handle!); + this.canceller = null; + if (result.ok) { + this.handle = result.value.handle; } + return result; } async doClaim(deviceLabel: string, userName: string, email: string): Promise<Result<UserClaimFinalizeInfo, ClaimInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - const result = await libparsec.claimerUserInProgress3DoClaim( - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this.canceller, - this.handle!, - deviceLabel, - { email: email, label: userName }, - ); - if (result.ok) { - this.handle = result.value.handle; - } - this.canceller = null; - return result; - } else { - await wait(MOCK_WAITING_TIME); - return { - ok: true, - value: { - handle: DEFAULT_HANDLE, - }, - }; + this.canceller = await libparsec.newCanceller(); + const result = await libparsec.claimerUserInProgress3DoClaim( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + this.canceller, + this.handle!, + deviceLabel, + { email: email, label: userName }, + ); + if (result.ok) { + this.handle = result.value.handle; } + this.canceller = null; + return result; } async finalize(saveStrategy: DeviceSaveStrategy): Promise<Result<AvailableDevice, ClaimInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - const result = await libparsec.claimerUserFinalizeSaveLocalDevice( - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this.handle!, - saveStrategy, - ); - if (result.ok) { - result.value.createdOn = DateTime.fromSeconds(result.value.createdOn as any as number); - result.value.protectedOn = DateTime.fromSeconds(result.value.protectedOn as any as number); - this.device = result.value; - } - this.handle = null; - return result; - } else { - this.handle = null; - this.device = { - keyFilePath: '/path', - serverUrl: 'https://parsec.invalid', - createdOn: DateTime.utc(), - protectedOn: DateTime.utc(), - organizationId: 'MyOrg', - userId: 'userid', - deviceId: 'deviceid', - humanHandle: { - label: 'A', - email: 'a@b.c', - }, - deviceLabel: 'a@b', - ty: DeviceFileType.Password, - }; - return { ok: true, value: this.device }; + const result = await libparsec.claimerUserFinalizeSaveLocalDevice( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + this.handle!, + saveStrategy, + ); + if (result.ok) { + result.value.createdOn = DateTime.fromSeconds(result.value.createdOn as any as number); + result.value.protectedOn = DateTime.fromSeconds(result.value.protectedOn as any as number); + this.device = result.value; } + this.handle = null; + return result; } } diff --git a/client/src/parsec/device.ts b/client/src/parsec/device.ts index 486bb42df9c..b0ac8f07594 100644 --- a/client/src/parsec/device.ts +++ b/client/src/parsec/device.ts @@ -1,7 +1,6 @@ // Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS -import { needsMocks } from '@/parsec/environment'; -import { getClientConfig, wait } from '@/parsec/internals'; +import { getClientConfig } from '@/parsec/internals'; import { getClientInfo } from '@/parsec/login'; import { getParsecHandle } from '@/parsec/routing'; import { @@ -11,18 +10,16 @@ import { ClientListUserDevicesError, ClientListUserDevicesErrorTag, ClientNewDeviceInvitationError, - DeviceFileType, DeviceInfo, DevicePurpose, DeviceSaveStrategy, ImportRecoveryDeviceError, - ImportRecoveryDeviceErrorTag, - InvitationEmailSentStatus, NewInvitationInfo, OwnDeviceInfo, Result, UserID, } from '@/parsec/types'; +import { generateNoHandleError } from '@/parsec/utils'; import { libparsec } from '@/plugins/libparsec'; import { DateTime } from 'luxon'; @@ -35,21 +32,10 @@ function generateRecoveryDeviceLabel(): string { export async function exportRecoveryDevice(): Promise<Result<[string, Uint8Array], ClientExportRecoveryDeviceError>> { const handle = getParsecHandle(); - if (handle !== null && !needsMocks()) { + if (handle !== null) { return await libparsec.clientExportRecoveryDevice(handle, generateRecoveryDeviceLabel()); - } else { - await wait(300); - return { - ok: true, - value: ['ABCDEF', new Uint8Array([0x6d, 0x65, 0x6f, 0x77])], - }; } -} - -function areArraysEqual(a: Uint8Array, b: Uint8Array): boolean { - return a.every((val, index) => { - return val === b[index]; - }); + return generateNoHandleError<ClientExportRecoveryDeviceError>(); } export async function importRecoveryDevice( @@ -58,47 +44,18 @@ export async function importRecoveryDevice( passphrase: string, saveStrategy: DeviceSaveStrategy, ): Promise<Result<AvailableDevice, ImportRecoveryDeviceError>> { - if (!needsMocks()) { - const result = await libparsec.importRecoveryDevice(getClientConfig(), recoveryData, passphrase, deviceLabel, saveStrategy); - if (result.ok) { - result.value.createdOn = DateTime.fromSeconds(result.value.createdOn as any as number); - result.value.protectedOn = DateTime.fromSeconds(result.value.protectedOn as any as number); - } - return result; + const result = await libparsec.importRecoveryDevice(getClientConfig(), recoveryData, passphrase, deviceLabel, saveStrategy); + if (result.ok) { + result.value.createdOn = DateTime.fromSeconds(result.value.createdOn as any as number); + result.value.protectedOn = DateTime.fromSeconds(result.value.protectedOn as any as number); } - - // cspell:disable-next-line - if (passphrase !== 'ABCD-EFGH-IJKL-MNOP-QRST-UVWX-YZ12-3456-7890-ABCD-EFGH-IJKL-MNOP') { - return { ok: false, error: { tag: ImportRecoveryDeviceErrorTag.InvalidPassphrase, error: 'Wrong passphrase' } }; - } - if (areArraysEqual(recoveryData, new Uint8Array([78, 79, 80, 10]))) { - return { ok: false, error: { tag: ImportRecoveryDeviceErrorTag.InvalidData, error: 'Wrong data' } }; - } - - return { - ok: true, - value: { - keyFilePath: 'dummy', - serverUrl: 'https://parsec.invalid', - createdOn: DateTime.utc(), - protectedOn: DateTime.utc(), - organizationId: 'dummy_org', - userId: 'dummy_user_id', - deviceId: 'device_id', - humanHandle: { - email: 'dummy_email@email.dum', - label: 'dummy_label', - }, - deviceLabel: deviceLabel, - ty: DeviceFileType.Password, - }, - }; + return result; } export async function listOwnDevices(): Promise<Result<Array<OwnDeviceInfo>, ClientListUserDevicesError>> { const handle = getParsecHandle(); - if (handle !== null && !needsMocks()) { + if (handle !== null) { const clientResult = await getClientInfo(); if (clientResult.ok) { @@ -118,28 +75,14 @@ export async function listOwnDevices(): Promise<Result<Array<OwnDeviceInfo>, Cli error: { tag: ClientListUserDevicesErrorTag.Internal, error: '' }, }; } - } else { - return { - ok: true, - value: [1, 2, 3].map((n) => { - return { - id: `device${n}`, - deviceLabel: n === 3 ? `${RECOVERY_DEVICE_PREFIX}_device${n}` : `device${n}`, - createdOn: DateTime.now(), - createdBy: 'some_device', - isCurrent: n === 1, - isRecovery: n === 3, - purpose: n === 3 ? DevicePurpose.PassphraseRecovery : DevicePurpose.Standard, - }; - }), - }; } + return generateNoHandleError<ClientListUserDevicesError>(); } export async function listUserDevices(user: UserID): Promise<Result<Array<DeviceInfo>, ClientListUserDevicesError>> { const handle = getParsecHandle(); - if (handle !== null && !needsMocks()) { + if (handle !== null) { const result = await libparsec.clientListUserDevices(handle, user); if (result.ok) { result.value.map((item) => { @@ -148,34 +91,8 @@ export async function listUserDevices(user: UserID): Promise<Result<Array<Device }); } return result; - } else { - return { - ok: true, - value: [ - { - id: 'device1', - deviceLabel: 'My First Device', - purpose: DevicePurpose.Standard, - createdOn: DateTime.now(), - createdBy: 'some_device', - }, - { - id: 'device2', - deviceLabel: 'My Second Device', - purpose: DevicePurpose.Standard, - createdOn: DateTime.now(), - createdBy: 'device1', - }, - { - id: `${RECOVERY_DEVICE_PREFIX}_device1`, - deviceLabel: 'Recovery First Device', - purpose: DevicePurpose.PassphraseRecovery, - createdOn: DateTime.now(), - createdBy: 'device1', - }, - ], - }; } + return generateNoHandleError<ClientListUserDevicesError>(); } export async function archiveDevice(device: AvailableDevice): Promise<Result<null, ArchiveDeviceError>> { @@ -185,19 +102,9 @@ export async function archiveDevice(device: AvailableDevice): Promise<Result<nul export async function createDeviceInvitation(sendEmail: boolean): Promise<Result<NewInvitationInfo, ClientNewDeviceInvitationError>> { const clientHandle = getParsecHandle(); - if (clientHandle !== null && !needsMocks()) { + if (clientHandle !== null) { const result = await libparsec.clientNewDeviceInvitation(clientHandle, sendEmail); return result; - } else { - return { - ok: true, - value: { - // cspell:disable-next-line - addr: 'parsec3://example.parsec.cloud/Org?a=claim_device&p=xBj1p7vXl_j1tzTjrx5pzbXV7XTbx_Xnnb0', - // cspell:disable-next-line - token: '9ae715f49bc0468eac211e1028f15529', - emailSentStatus: InvitationEmailSentStatus.Success, - }, - }; } + return generateNoHandleError<ClientNewDeviceInvitationError>(); } diff --git a/client/src/parsec/environment.ts b/client/src/parsec/environment.ts index b7927cda50b..b3491fb377f 100644 --- a/client/src/parsec/environment.ts +++ b/client/src/parsec/environment.ts @@ -33,13 +33,6 @@ export function usesTestbed(): boolean { return window.usesTestbed(); } -// Whether or not module functions should return mock values. -// Currently, this can be used on web, since the bindings are not fully -// implemented, but it could also prove useful when in a testing environment. -export function needsMocks(): boolean { - return !isDesktop(); -} - export function isElectron(): boolean { return isPlatform('electron'); } diff --git a/client/src/parsec/file.ts b/client/src/parsec/file.ts index c3a11b14e40..22cd4b7fd0c 100644 --- a/client/src/parsec/file.ts +++ b/client/src/parsec/file.ts @@ -1,11 +1,6 @@ // Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS -import { needsMocks } from '@/parsec/environment'; -import { wait } from '@/parsec/internals'; -import { MockFileType, getMockFileContent } from '@/parsec/mock_files'; -import { MockEntry, generateEntriesForEachFileType, generateFile, generateFolder } from '@/parsec/mock_generator'; import { Path } from '@/parsec/path'; -import { getParsecHandle, getWorkspaceHandle } from '@/parsec/routing'; import { EntryName, EntryStat, @@ -23,15 +18,10 @@ import { Result, WorkspaceCreateFileError, WorkspaceCreateFolderError, - WorkspaceCreateFolderErrorTag, WorkspaceFdCloseError, - WorkspaceFdCloseErrorTag, WorkspaceFdReadError, - WorkspaceFdReadErrorTag, WorkspaceFdResizeError, - WorkspaceFdResizeErrorTag, WorkspaceFdWriteError, - WorkspaceFdWriteErrorTag, WorkspaceHandle, WorkspaceMoveEntryError, WorkspaceOpenFileError, @@ -42,41 +32,22 @@ import { import { MoveEntryModeTag, libparsec } from '@/plugins/libparsec'; import { DateTime } from 'luxon'; -const MOCK_OPENED_FILES = new Map<FileDescriptor, FsPath>(); -let MOCK_CURRENT_FD = 1; - export const DEFAULT_READ_SIZE = 256_000; export async function createFile(workspaceHandle: WorkspaceHandle, path: FsPath): Promise<Result<FileID, WorkspaceCreateFileError>> { - if (!needsMocks()) { - return await libparsec.workspaceCreateFile(workspaceHandle, path); - } else { - return { ok: true, value: '42' }; - } + return await libparsec.workspaceCreateFile(workspaceHandle, path); } export async function createFolder(workspaceHandle: WorkspaceHandle, path: FsPath): Promise<Result<FileID, WorkspaceCreateFolderError>> { - if (!needsMocks()) { - return await libparsec.workspaceCreateFolderAll(workspaceHandle, path); - } else { - return { ok: false, error: { tag: WorkspaceCreateFolderErrorTag.EntryExists, error: 'already exists' } }; - } + return await libparsec.workspaceCreateFolderAll(workspaceHandle, path); } export async function deleteFile(workspaceHandle: WorkspaceHandle, path: FsPath): Promise<Result<null, WorkspaceRemoveEntryError>> { - if (!needsMocks()) { - return await libparsec.workspaceRemoveFile(workspaceHandle, path); - } else { - return { ok: true, value: null }; - } + return await libparsec.workspaceRemoveFile(workspaceHandle, path); } export async function deleteFolder(workspaceHandle: WorkspaceHandle, path: FsPath): Promise<Result<null, WorkspaceRemoveEntryError>> { - if (!needsMocks()) { - return await libparsec.workspaceRemoveFolderAll(workspaceHandle, path); - } else { - return { ok: true, value: null }; - } + return await libparsec.workspaceRemoveFolderAll(workspaceHandle, path); } export async function rename( @@ -84,58 +55,35 @@ export async function rename( path: FsPath, newName: EntryName, ): Promise<Result<FsPath, WorkspaceMoveEntryError>> { - if (!needsMocks()) { - const newPath = await Path.join(await Path.parent(path), newName); - const result = await libparsec.workspaceMoveEntry(workspaceHandle, path, newPath, { tag: MoveEntryModeTag.NoReplace }); - if (result.ok) { - return { ok: true, value: newPath }; - } - return result; - } else { - return { ok: true, value: '/a/b.txt' }; + const newPath = await Path.join(await Path.parent(path), newName); + const result = await libparsec.workspaceMoveEntry(workspaceHandle, path, newPath, { tag: MoveEntryModeTag.NoReplace }); + if (result.ok) { + return { ok: true, value: newPath }; } + return result; } -let MOCK_FILE_ID = 1; - export async function entryStat(workspaceHandle: WorkspaceHandle, path: FsPath): Promise<Result<EntryStat, WorkspaceStatEntryError>> { const fileName = (await Path.filename(path)) || ''; - if (!needsMocks()) { - const result = await libparsec.workspaceStatEntry(workspaceHandle, path); - if (result.ok) { - result.value.created = DateTime.fromSeconds(result.value.created as any as number); - result.value.updated = DateTime.fromSeconds(result.value.updated as any as number); - if (result.value.tag === FileType.File) { - (result.value as EntryStatFile).isFile = (): boolean => true; - (result.value as EntryStatFile).name = fileName; - (result.value as EntryStatFile).path = path; - (result.value as EntryStatFile).isConfined = (): boolean => result.value.confinementPoint !== null; - } else { - (result.value as EntryStatFolder).isFile = (): boolean => false; - (result.value as EntryStatFolder).name = fileName; - (result.value as EntryStatFolder).path = path; - (result.value as EntryStatFolder).isConfined = (): boolean => result.value.confinementPoint !== null; - } + const result = await libparsec.workspaceStatEntry(workspaceHandle, path); + if (result.ok) { + result.value.created = DateTime.fromSeconds(result.value.created as any as number); + result.value.updated = DateTime.fromSeconds(result.value.updated as any as number); + if (result.value.tag === FileType.File) { + (result.value as EntryStatFile).size = result.value.size; + (result.value as EntryStatFile).isFile = (): boolean => true; + (result.value as EntryStatFile).name = fileName; + (result.value as EntryStatFile).path = path; + (result.value as EntryStatFile).isConfined = (): boolean => result.value.confinementPoint !== null; + } else { + (result.value as EntryStatFolder).isFile = (): boolean => false; + (result.value as EntryStatFolder).name = fileName; + (result.value as EntryStatFolder).path = path; + (result.value as EntryStatFolder).isConfined = (): boolean => result.value.confinementPoint !== null; } - return result as Result<EntryStat, WorkspaceStatEntryError>; - } - - MOCK_FILE_ID += 1; - - let entry: MockEntry; - - if (path !== '/' && fileName.startsWith('File_')) { - entry = await generateFile(await Path.parent(path), { parentId: `${MOCK_FILE_ID}`, fileName: fileName }); - } else { - entry = await generateFolder(path, { parentId: `${MOCK_FILE_ID}`, fileName: fileName }); } - (entry as any as EntryStat).baseVersion = entry.version; - (entry as any as EntryStat).confinementPoint = null; - (entry as any as EntryStat).isConfined = (): boolean => false; - (entry as any as EntryStat).needSync = Math.floor(Math.random() * 2) === 1; - (entry as any as EntryStat).isPlaceholder = false; - return { ok: true, value: entry as any as EntryStat }; + return result as Result<EntryStat, WorkspaceStatEntryError>; } export async function statFolderChildren( @@ -143,56 +91,47 @@ export async function statFolderChildren( path: FsPath, excludeConfined = true, ): Promise<Result<Array<EntryStat>, WorkspaceStatFolderChildrenError>> { - if (!needsMocks()) { - const watchResult = await libparsec.workspaceWatchEntryOneshot(workspaceHandle, path); + const watchResult = await libparsec.workspaceWatchEntryOneshot(workspaceHandle, path); - let result; - if (!watchResult.ok) { - result = await libparsec.workspaceStatFolderChildren(workspaceHandle, path); - } else { - result = await libparsec.workspaceStatFolderChildrenById(workspaceHandle, watchResult.value); - } + let result; + if (!watchResult.ok) { + result = await libparsec.workspaceStatFolderChildren(workspaceHandle, path); + } else { + result = await libparsec.workspaceStatFolderChildrenById(workspaceHandle, watchResult.value); + } - if (!result.ok) { - return result; - } + if (!result.ok) { + return result; + } - const cooked: Array<EntryStat> = []; - for (const [name, stat] of result.value) { - if (!stat.confinementPoint || !excludeConfined) { - stat.created = DateTime.fromSeconds(stat.created as any as number); - stat.updated = DateTime.fromSeconds(stat.updated as any as number); - if (stat.tag === FileType.File) { - (stat as EntryStatFile).isFile = (): boolean => true; - (stat as EntryStatFile).name = name; - (stat as EntryStatFile).path = await Path.join(path, name); - (stat as EntryStatFile).isConfined = (): boolean => stat.confinementPoint !== null; - } else { - (stat as EntryStatFolder).isFile = (): boolean => false; - (stat as EntryStatFolder).name = name; - (stat as EntryStatFolder).path = await Path.join(path, name); - (stat as EntryStatFolder).isConfined = (): boolean => stat.confinementPoint !== null; - } - cooked.push(stat as EntryStat); + const cooked: Array<EntryStat> = []; + for (const [name, stat] of result.value) { + if (name === undefined || stat === undefined) { + continue; + } + if (!stat.confinementPoint || !excludeConfined) { + stat.created = DateTime.fromSeconds(stat.created as any as number); + stat.updated = DateTime.fromSeconds(stat.updated as any as number); + if (stat.tag === FileType.File) { + (stat as EntryStatFile).size = stat.size; + (stat as EntryStatFile).isFile = (): boolean => true; + (stat as EntryStatFile).name = name; + (stat as EntryStatFile).path = await Path.join(path, name); + (stat as EntryStatFile).isConfined = (): boolean => stat.confinementPoint !== null; + } else { + (stat as EntryStatFolder).isFile = (): boolean => false; + (stat as EntryStatFolder).name = name; + (stat as EntryStatFolder).path = await Path.join(path, name); + (stat as EntryStatFolder).isConfined = (): boolean => stat.confinementPoint !== null; } + cooked.push(stat as EntryStat); } - - return { - ok: true, - value: cooked, - }; } - await wait(500); - const items = (await generateEntriesForEachFileType(path)).map((entry) => { - (entry as any as EntryStat).baseVersion = entry.version; - (entry as any as EntryStat).confinementPoint = null; - (entry as any as EntryStat).isConfined = (): boolean => false; - (entry as any as EntryStat).needSync = Math.floor(Math.random() * 2) === 1; - (entry as any as EntryStat).isPlaceholder = false; - return entry as any as EntryStat; - }); - return { ok: true, value: items }; + return { + ok: true, + value: cooked, + }; } export async function moveEntry( @@ -201,16 +140,12 @@ export async function moveEntry( destination: FsPath, forceReplace = false, ): Promise<Result<null, WorkspaceMoveEntryError>> { - if (workspaceHandle && !needsMocks()) { - return libparsec.workspaceMoveEntry( - workspaceHandle, - source, - destination, - forceReplace ? { tag: MoveEntryModeTag.CanReplace } : { tag: MoveEntryModeTag.NoReplace }, - ); - } else { - return { ok: true, value: null }; - } + return libparsec.workspaceMoveEntry( + workspaceHandle, + source, + destination, + forceReplace ? { tag: MoveEntryModeTag.CanReplace } : { tag: MoveEntryModeTag.NoReplace }, + ); } export enum CopyErrorTag { @@ -221,17 +156,6 @@ export interface CopyError { tag: CopyErrorTag.Internal; } -export async function copyEntry(_source: FsPath, _destination: FsPath): Promise<Result<null, CopyError>> { - const clientHandle = getParsecHandle(); - const workspaceHandle = getWorkspaceHandle(); - - if (clientHandle && workspaceHandle && !needsMocks()) { - return { ok: true, value: null }; - } else { - return { ok: true, value: null }; - } -} - export async function parseFileLink(link: string): Promise<Result<ParsedParsecAddrWorkspacePath, ParseParsecAddrError>> { const result = await libparsec.parseParsecAddr(link); if (result.ok && result.value.tag !== ParsedParsecAddrTag.WorkspacePath) { @@ -297,26 +221,11 @@ export async function openFile( createNew: options.createNew ? true : false, }; - if (workspaceHandle && !needsMocks()) { - return await libparsec.workspaceOpenFile(workspaceHandle, path, parsecOptions); - } else { - const fd = MOCK_CURRENT_FD; - MOCK_CURRENT_FD += 1; - MOCK_OPENED_FILES.set(fd, path); - return { ok: true, value: fd }; - } + return await libparsec.workspaceOpenFile(workspaceHandle, path, parsecOptions); } export async function closeFile(workspaceHandle: WorkspaceHandle, fd: FileDescriptor): Promise<Result<null, WorkspaceFdCloseError>> { - if (!needsMocks()) { - return await libparsec.workspaceFdClose(workspaceHandle, fd); - } else { - if (!MOCK_OPENED_FILES.has(fd)) { - return { ok: false, error: { tag: WorkspaceFdCloseErrorTag.BadFileDescriptor, error: 'Invalid file descriptor' } }; - } - MOCK_OPENED_FILES.delete(fd); - return { ok: true, value: null }; - } + return await libparsec.workspaceFdClose(workspaceHandle, fd); } export async function resizeFile( @@ -324,14 +233,7 @@ export async function resizeFile( fd: FileDescriptor, length: number, ): Promise<Result<null, WorkspaceFdResizeError>> { - if (workspaceHandle && !needsMocks()) { - return await libparsec.workspaceFdResize(workspaceHandle, fd, length, true); - } else { - if (!MOCK_OPENED_FILES.has(fd)) { - return { ok: false, error: { tag: WorkspaceFdResizeErrorTag.BadFileDescriptor, error: 'Invalid file descriptor' } }; - } - return { ok: true, value: null }; - } + return await libparsec.workspaceFdResize(workspaceHandle, fd, BigInt(length), true); } export async function writeFile( @@ -340,15 +242,11 @@ export async function writeFile( offset: number, data: Uint8Array, ): Promise<Result<number, WorkspaceFdWriteError>> { - if (!needsMocks()) { - return await libparsec.workspaceFdWrite(workspaceHandle, fd, offset, data); - } else { - if (!MOCK_OPENED_FILES.has(fd)) { - return { ok: false, error: { tag: WorkspaceFdWriteErrorTag.BadFileDescriptor, error: 'Invalid file descriptor' } }; - } - await wait(100); - return { ok: true, value: data.length }; + const result = await libparsec.workspaceFdWrite(workspaceHandle, fd, BigInt(offset), data); + if (result.ok) { + return { ok: true, value: Number(result.value) }; } + return result; } export async function readFile( @@ -357,56 +255,7 @@ export async function readFile( offset: number, size: number, ): Promise<Result<Uint8Array, WorkspaceFdReadError>> { - if (!needsMocks()) { - return await libparsec.workspaceFdRead(workspaceHandle, fd, offset, size); - } else { - if (!MOCK_OPENED_FILES.has(fd)) { - return { ok: false, error: { tag: WorkspaceFdReadErrorTag.BadFileDescriptor, error: 'Invalid file descriptor' } }; - } - await wait(100); - const path = MOCK_OPENED_FILES.get(fd) as string; - const fileName = (await Path.filename(path)) as EntryName; - const ext = Path.getFileExtension(fileName); - - switch (ext) { - case 'xlsx': - offset === 0 && console.log('Using XLSX content'); - return { ok: true, value: (await getMockFileContent(MockFileType.XLSX)).slice(offset, offset + size) }; - case 'png': - offset === 0 && console.log('Using PNG content'); - return { ok: true, value: (await getMockFileContent(MockFileType.PNG)).slice(offset, offset + size) }; - case 'jpg': - offset === 0 && console.log('Using JPG content'); - return { ok: true, value: (await getMockFileContent(MockFileType.JPG)).slice(offset, offset + size) }; - case 'docx': - offset === 0 && console.log('Using DOCX content'); - return { ok: true, value: (await getMockFileContent(MockFileType.DOCX)).slice(offset, offset + size) }; - case 'txt': - offset === 0 && console.log('Using TXT content'); - return { ok: true, value: (await getMockFileContent(MockFileType.TXT)).slice(offset, offset + size) }; - case 'py': - offset === 0 && console.log('Using PY content'); - return { ok: true, value: (await getMockFileContent(MockFileType.PY)).slice(offset, offset + size) }; - case 'pdf': - offset === 0 && console.log('Using PDF content'); - return { ok: true, value: (await getMockFileContent(MockFileType.PDF)).slice(offset, offset + size) }; - case 'mp3': - offset === 0 && console.log('Using MP3 content'); - return { ok: true, value: (await getMockFileContent(MockFileType.MP3)).slice(offset, offset + size) }; - case 'mp4': - offset === 0 && console.log('Using MP4 content'); - return { ok: true, value: (await getMockFileContent(MockFileType.MP4)).slice(offset, offset + size) }; - } - console.log('Using default file content'); - return { - ok: true, - value: new Uint8Array([ - 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 5, 0, 0, 0, 5, 8, 6, 0, 0, 0, 141, 111, 38, 229, 0, 0, 0, 28, - 73, 68, 65, 84, 8, 215, 99, 248, 255, 255, 63, 195, 127, 6, 32, 5, 195, 32, 18, 132, 208, 49, 241, 130, 88, 205, 4, 0, 14, 245, 53, - 203, 209, 142, 14, 31, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130, - ]), - }; - } + return await libparsec.workspaceFdRead(workspaceHandle, fd, BigInt(offset), BigInt(size)); } export interface EntryTree { @@ -447,7 +296,7 @@ export async function listTree(workspaceHandle: WorkspaceHandle, path: FsPath, d tree.maxFilesReached = true; } } else { - tree.totalSize += (entry as EntryStatFile).size; + tree.totalSize += Number((entry as EntryStatFile).size); tree.entries.push(entry as EntryStatFile); if (tree.entries.length > filesLimit) { tree.maxFilesReached = true; diff --git a/client/src/parsec/greet_device.ts b/client/src/parsec/greet_device.ts index 223ea15307d..8bdf89926b2 100644 --- a/client/src/parsec/greet_device.ts +++ b/client/src/parsec/greet_device.ts @@ -15,9 +15,8 @@ import { Result, createDeviceInvitation, } from '@/parsec'; -import { needsMocks } from '@/parsec/environment'; -import { DEFAULT_HANDLE, MOCK_WAITING_TIME, wait } from '@/parsec/internals'; import { getParsecHandle } from '@/parsec/routing'; +import { generateNoHandleError } from '@/parsec/utils'; import { InvitationToken, ParsecInvitationAddr, SASCode, libparsec } from '@/plugins/libparsec'; export class DeviceGreet { @@ -42,10 +41,10 @@ export class DeviceGreet { } async abort(): Promise<void> { - if (this.canceller !== null && !needsMocks()) { + if (this.canceller !== null) { await libparsec.cancel(this.canceller); } - if (this.handle !== null && !needsMocks()) { + if (this.handle !== null) { await libparsec.claimerGreeterAbortOperation(this.handle); } this.canceller = null; @@ -91,152 +90,101 @@ export class DeviceGreet { async sendEmail(): Promise<boolean> { const clientHandle = getParsecHandle(); - if (clientHandle !== null && !needsMocks()) { + if (clientHandle !== null) { const result = await libparsec.clientNewDeviceInvitation(clientHandle, true); return result.ok; - } else { - return true; } + return false; } async startGreet(): Promise<Result<DeviceGreetInitialInfo, ClientStartInvitationGreetError>> { this._assertState(true, true); const clientHandle = getParsecHandle(); - if (clientHandle !== null && !needsMocks()) { + if (clientHandle !== null) { const result = await libparsec.clientStartDeviceInvitationGreet(clientHandle, this.token); if (result.ok) { this.handle = result.value.handle; } return result; - } else { - this.handle = DEFAULT_HANDLE; - await wait(MOCK_WAITING_TIME); - return { ok: true, value: { handle: DEFAULT_HANDLE } }; } + return generateNoHandleError<ClientStartInvitationGreetError>(); } async initialWaitGuest(): Promise<Result<DeviceGreetInProgress1Info, GreetInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const result = await libparsec.greeterDeviceInitialDoWaitPeer(this.canceller, this.handle!); - this.canceller = null; - if (result.ok) { - this.handle = result.value.handle; - this.hostSASCode = result.value.greeterSas; - } - return result; - } else { - this.hostSASCode = '2EDF'; - return { - ok: true, - value: { handle: DEFAULT_HANDLE, greeterSas: this.hostSASCode }, - }; + this.canceller = await libparsec.newCanceller(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const result = await libparsec.greeterDeviceInitialDoWaitPeer(this.canceller, this.handle!); + this.canceller = null; + if (result.ok) { + this.handle = result.value.handle; + this.hostSASCode = result.value.greeterSas; } + return result; } async waitGuestTrust(): Promise<Result<DeviceGreetInProgress2Info, GreetInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const result = await libparsec.greeterDeviceInProgress1DoWaitPeerTrust(this.canceller, this.handle!); - if (result.ok) { - this.handle = result.value.handle; - this.SASCodeChoices = result.value.claimerSasChoices; - this.correctSASCode = result.value.claimerSas; - } - this.canceller = null; - return result; - } else { - await wait(MOCK_WAITING_TIME); - this.SASCodeChoices = ['1ABC', '2DEF', '3GHI', '4JKL']; - this.correctSASCode = '2DEF'; - return { - ok: true, - value: { - handle: DEFAULT_HANDLE, - claimerSasChoices: this.SASCodeChoices, - claimerSas: this.correctSASCode, - }, - }; + this.canceller = await libparsec.newCanceller(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const result = await libparsec.greeterDeviceInProgress1DoWaitPeerTrust(this.canceller, this.handle!); + if (result.ok) { + this.handle = result.value.handle; + this.SASCodeChoices = result.value.claimerSasChoices; + this.correctSASCode = result.value.claimerSas; } + this.canceller = null; + return result; } async denyTrust(): Promise<Result<null, GreetInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const result = await libparsec.greeterDeviceInProgress2DoDenyTrust(this.canceller, this.handle!); - this.handle = null; - this.canceller = null; - return result; - } else { - return { ok: true, value: null }; - } + this.canceller = await libparsec.newCanceller(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const result = await libparsec.greeterDeviceInProgress2DoDenyTrust(this.canceller, this.handle!); + this.handle = null; + this.canceller = null; + return result; } async signifyTrust(): Promise<Result<DeviceGreetInProgress3Info, GreetInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const result = await libparsec.greeterDeviceInProgress2DoSignifyTrust(this.canceller, this.handle!); - if (result.ok) { - this.handle = result.value.handle; - } - this.canceller = null; - return result; - } else { - return { ok: true, value: { handle: DEFAULT_HANDLE } }; + this.canceller = await libparsec.newCanceller(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const result = await libparsec.greeterDeviceInProgress2DoSignifyTrust(this.canceller, this.handle!); + if (result.ok) { + this.handle = result.value.handle; } + this.canceller = null; + return result; } async getClaimRequests(): Promise<Result<DeviceGreetInProgress4Info, GreetInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const result = await libparsec.greeterDeviceInProgress3DoGetClaimRequests(this.canceller, this.handle!); - this.canceller = null; - if (result.ok) { - this.handle = result.value.handle; - this.requestedDeviceLabel = result.value.requestedDeviceLabel || ''; - } - return result; - } else { - await wait(MOCK_WAITING_TIME); - this.requestedDeviceLabel = 'My Device'; - return { - ok: true, - value: { - handle: DEFAULT_HANDLE, - requestedDeviceLabel: this.requestedDeviceLabel, - }, - }; + this.canceller = await libparsec.newCanceller(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const result = await libparsec.greeterDeviceInProgress3DoGetClaimRequests(this.canceller, this.handle!); + this.canceller = null; + if (result.ok) { + this.handle = result.value.handle; + this.requestedDeviceLabel = result.value.requestedDeviceLabel || ''; } + return result; } async createDevice(): Promise<Result<null, GreetInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - const result = await libparsec.greeterDeviceInProgress4DoCreate( - this.canceller, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this.handle!, - this.requestedDeviceLabel, - ); - this.canceller = null; - this.handle = null; - return result; - } else { - this.handle = null; - return { ok: true, value: null }; - } + this.canceller = await libparsec.newCanceller(); + const result = await libparsec.greeterDeviceInProgress4DoCreate( + this.canceller, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + this.handle!, + this.requestedDeviceLabel, + ); + this.canceller = null; + this.handle = null; + return result; } } diff --git a/client/src/parsec/greet_user.ts b/client/src/parsec/greet_user.ts index 0aefe89c368..da4db4d93d7 100644 --- a/client/src/parsec/greet_user.ts +++ b/client/src/parsec/greet_user.ts @@ -15,9 +15,8 @@ import { UserGreetInitialInfo, UserProfile, } from '@/parsec'; -import { needsMocks } from '@/parsec/environment'; -import { DEFAULT_HANDLE, MOCK_WAITING_TIME, wait } from '@/parsec/internals'; import { getParsecHandle } from '@/parsec/routing'; +import { generateNoHandleError } from '@/parsec/utils'; import { SASCode, libparsec } from '@/plugins/libparsec'; export class UserGreet { @@ -40,10 +39,10 @@ export class UserGreet { } async abort(): Promise<void> { - if (this.canceller !== null && !needsMocks()) { + if (this.canceller !== null) { await libparsec.cancel(this.canceller); } - if (this.handle !== null && !needsMocks()) { + if (this.handle !== null) { await libparsec.claimerGreeterAbortOperation(this.handle); } this.canceller = null; @@ -69,151 +68,93 @@ export class UserGreet { async startGreet(token: InvitationToken): Promise<Result<UserGreetInitialInfo, ClientStartInvitationGreetError>> { const clientHandle = getParsecHandle(); - if (clientHandle !== null && !needsMocks()) { + if (clientHandle !== null) { const result = await libparsec.clientStartUserInvitationGreet(clientHandle, token); if (result.ok) { this.handle = result.value.handle; } return result; - } else { - this.handle = DEFAULT_HANDLE; - await wait(MOCK_WAITING_TIME); - return { ok: true, value: { handle: DEFAULT_HANDLE } }; } + return generateNoHandleError<ClientStartInvitationGreetError>(); } async initialWaitGuest(): Promise<Result<UserGreetInProgress1Info, GreetInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const result = await libparsec.greeterUserInitialDoWaitPeer(this.canceller, this.handle!); - this.canceller = null; - if (result.ok) { - this.handle = result.value.handle; - this.hostSASCode = result.value.greeterSas; - } - return result; - } else { - await wait(MOCK_WAITING_TIME); - this.hostSASCode = '2EDF'; - return { - ok: true, - value: { handle: DEFAULT_HANDLE, greeterSas: this.hostSASCode }, - }; + this.canceller = await libparsec.newCanceller(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const result = await libparsec.greeterUserInitialDoWaitPeer(this.canceller, this.handle!); + this.canceller = null; + if (result.ok) { + this.handle = result.value.handle; + this.hostSASCode = result.value.greeterSas; } + return result; } async waitGuestTrust(): Promise<Result<UserGreetInProgress2Info, GreetInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const result = await libparsec.greeterUserInProgress1DoWaitPeerTrust(this.canceller, this.handle!); - if (result.ok) { - this.handle = result.value.handle; - this.SASCodeChoices = result.value.claimerSasChoices; - this.correctSASCode = result.value.claimerSas; - } - this.canceller = null; - return result; - } else { - await wait(MOCK_WAITING_TIME); - this.SASCodeChoices = ['1ABC', '2DEF', '3GHI', '4JKL']; - this.correctSASCode = '2DEF'; - return { - ok: true, - value: { - handle: DEFAULT_HANDLE, - claimerSasChoices: this.SASCodeChoices, - claimerSas: this.correctSASCode, - }, - }; + this.canceller = await libparsec.newCanceller(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const result = await libparsec.greeterUserInProgress1DoWaitPeerTrust(this.canceller, this.handle!); + if (result.ok) { + this.handle = result.value.handle; + this.SASCodeChoices = result.value.claimerSasChoices; + this.correctSASCode = result.value.claimerSas; } + this.canceller = null; + return result; } async denyTrust(): Promise<Result<null, GreetInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const result = await libparsec.greeterUserInProgress2DoDenyTrust(this.canceller, this.handle!); - this.handle = null; - this.canceller = null; - return result; - } else { - return { ok: true, value: null }; - } + this.canceller = await libparsec.newCanceller(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const result = await libparsec.greeterUserInProgress2DoDenyTrust(this.canceller, this.handle!); + this.handle = null; + this.canceller = null; + return result; } async signifyTrust(): Promise<Result<UserGreetInProgress3Info, GreetInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const result = await libparsec.greeterUserInProgress2DoSignifyTrust(this.canceller, this.handle!); - if (result.ok) { - this.handle = result.value.handle; - } - this.canceller = null; - return result; - } else { - await wait(MOCK_WAITING_TIME); - return { ok: true, value: { handle: DEFAULT_HANDLE } }; + this.canceller = await libparsec.newCanceller(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const result = await libparsec.greeterUserInProgress2DoSignifyTrust(this.canceller, this.handle!); + if (result.ok) { + this.handle = result.value.handle; } + this.canceller = null; + return result; } async getClaimRequests(): Promise<Result<UserGreetInProgress4Info, GreetInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const result = await libparsec.greeterUserInProgress3DoGetClaimRequests(this.canceller, this.handle!); - this.canceller = null; - if (result.ok) { - this.handle = result.value.handle; - this.requestedHumanHandle = result.value.requestedHumanHandle; - this.requestedDeviceLabel = result.value.requestedDeviceLabel || ''; - } - return result; - } else { - await wait(MOCK_WAITING_TIME); - this.requestedHumanHandle = { - label: 'Gordon Freeman', - email: 'gordon.freeman@blackmesa.nm', - }; - this.requestedDeviceLabel = 'My Device'; - return { - ok: true, - value: { - handle: DEFAULT_HANDLE, - requestedDeviceLabel: this.requestedDeviceLabel, - requestedHumanHandle: this.requestedHumanHandle, - }, - }; + this.canceller = await libparsec.newCanceller(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const result = await libparsec.greeterUserInProgress3DoGetClaimRequests(this.canceller, this.handle!); + this.canceller = null; + if (result.ok) { + this.handle = result.value.handle; + this.requestedHumanHandle = result.value.requestedHumanHandle; + this.requestedDeviceLabel = result.value.requestedDeviceLabel || ''; } + return result; } async createUser(humanHandle: HumanHandle, profile: UserProfile): Promise<Result<null, GreetInProgressError>> { this._assertState(true, false); - if (!needsMocks()) { - this.canceller = await libparsec.newCanceller(); - const result = await libparsec.greeterUserInProgress4DoCreate( - this.canceller, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this.handle!, - humanHandle, - this.requestedDeviceLabel, - profile, - ); - this.canceller = null; - this.handle = null; - return result; - } else { - await wait(500); - this.handle = null; - return { ok: true, value: null }; - } + this.canceller = await libparsec.newCanceller(); + const result = await libparsec.greeterUserInProgress4DoCreate( + this.canceller, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + this.handle!, + humanHandle, + this.requestedDeviceLabel, + profile, + ); + this.canceller = null; + this.handle = null; + return result; } } diff --git a/client/src/parsec/history.ts b/client/src/parsec/history.ts index 4bf0412fce3..960bdd30a01 100644 --- a/client/src/parsec/history.ts +++ b/client/src/parsec/history.ts @@ -1,13 +1,8 @@ // Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS -import { needsMocks } from '@/parsec/environment'; -import { wait } from '@/parsec/internals'; -import { MockFileType, getMockFileContent } from '@/parsec/mock_files'; -import { generateEntriesForEachFileType, generateFile, generateFolder } from '@/parsec/mock_generator'; import { Path } from '@/parsec/path'; import { getParsecHandle } from '@/parsec/routing'; import { - EntryName, FileDescriptor, FsPath, Result, @@ -33,15 +28,10 @@ import { WorkspaceHistoryHandle, WorkspaceID, } from '@/parsec/types'; +import { generateNoHandleError } from '@/parsec/utils'; import { libparsec } from '@/plugins/libparsec'; import { DateTime } from 'luxon'; -const MOCK_OPENED_FILES = new Map<FileDescriptor, FsPath>(); -let MOCK_CURRENT_FD = 1; - -const MOCK_OPENED_HISTORY = new Map<WorkspaceHistoryHandle, WorkspaceID>(); -let MOCK_OPEN_HISTORY_FD = 1; - export class WorkspaceHistory { private workspaceId: WorkspaceID; private handle?: WorkspaceHistoryHandle; @@ -85,113 +75,76 @@ export class WorkspaceHistory { return { ok: true, value: this.handle }; } const connectionHandle = getParsecHandle(); - if (connectionHandle && !needsMocks()) { - const result = await libparsec.clientStartWorkspaceHistory2(connectionHandle, this.workspaceId); - if (result.ok) { - this.handle = result.value; - const upperBoundResult = await libparsec.workspaceHistory2GetTimestampHigherBound(result.value); - if (upperBoundResult.ok) { - this.upperBound = DateTime.fromSeconds(upperBoundResult.value as any as number); - } - const lowerBoundResult = await libparsec.workspaceHistory2GetTimestampLowerBound(result.value); - if (lowerBoundResult.ok) { - this.lowerBound = DateTime.fromSeconds(lowerBoundResult.value as any as number); - } - if (currentTime) { - await this.setCurrentTime(currentTime); - } else { - const toiResult = await libparsec.workspaceHistory2GetTimestampOfInterest(result.value); - if (toiResult.ok) { - this.currentTime = DateTime.fromSeconds(toiResult.value as any as number); - } - } + if (!connectionHandle) { + return generateNoHandleError<WorkspaceHistory2StartError>(); + } + const result = await libparsec.clientStartWorkspaceHistory2(connectionHandle, this.workspaceId); + if (result.ok) { + this.handle = result.value; + const upperBoundResult = await libparsec.workspaceHistory2GetTimestampHigherBound(result.value); + if (upperBoundResult.ok) { + this.upperBound = DateTime.fromSeconds(upperBoundResult.value as any as number); } - return result; - } else { - if (Array.from(MOCK_OPENED_HISTORY.values()).find((v) => v === this.workspaceId) !== undefined) { - console.log('This workspace already has an opened history'); + const lowerBoundResult = await libparsec.workspaceHistory2GetTimestampLowerBound(result.value); + if (lowerBoundResult.ok) { + this.lowerBound = DateTime.fromSeconds(lowerBoundResult.value as any as number); } - const fd = MOCK_OPEN_HISTORY_FD; - this.handle = fd; - MOCK_OPEN_HISTORY_FD += 1; - MOCK_OPENED_HISTORY.set(fd, this.workspaceId); - this.upperBound = DateTime.now(); - this.lowerBound = DateTime.now().minus({ months: 4 }); if (currentTime) { await this.setCurrentTime(currentTime); } else { - this.currentTime = this.upperBound; + const toiResult = await libparsec.workspaceHistory2GetTimestampOfInterest(result.value); + if (toiResult.ok) { + this.currentTime = DateTime.fromSeconds(toiResult.value as any as number); + } } - return { ok: true, value: fd }; } + return result; } async stop(): Promise<Result<null, WorkspaceHistory2InternalOnlyError>> { if (this.handle === undefined) { return { ok: false, error: { tag: WorkspaceHistory2InternalOnlyErrorTag.Internal, error: 'Not started' } }; } - if (!needsMocks()) { - const result = await libparsec.workspaceHistory2Stop(this.handle); - this.reset(); - return result; - } else { - if (!MOCK_OPENED_HISTORY.has(this.handle)) { - return { ok: false, error: { tag: WorkspaceHistory2InternalOnlyErrorTag.Internal, error: 'Not started' } }; - } - MOCK_OPENED_HISTORY.delete(this.handle); - this.handle = undefined; - } - return { ok: true, value: null }; + const result = await libparsec.workspaceHistory2Stop(this.handle); + this.reset(); + return result; } async setCurrentTime(time: DateTime): Promise<Result<null, WorkspaceHistory2SetTimestampOfInterestError>> { if (this.handle === undefined) { return { ok: false, error: { tag: WorkspaceHistory2SetTimestampOfInterestErrorTag.Internal, error: 'Not started' } }; } - if (!needsMocks()) { - const result = await libparsec.workspaceHistory2SetTimestampOfInterest(this.handle, time.toSeconds() as any as DateTime); - if (result.ok) { - this.currentTime = time; - } - return result; - } else { + const result = await libparsec.workspaceHistory2SetTimestampOfInterest(this.handle, time.toSeconds() as any as DateTime); + if (result.ok) { this.currentTime = time; - return { ok: true, value: null }; } + return result; } async statFolderChildren(path: FsPath): Promise<Result<Array<WorkspaceHistoryEntryStat>, WorkspaceHistory2StatFolderChildrenError>> { if (this.handle === undefined) { return { ok: false, error: { tag: WorkspaceHistory2StatFolderChildrenErrorTag.Internal, error: 'Not started' } }; } - if (!needsMocks()) { - const result = await libparsec.workspaceHistory2StatFolderChildren(this.handle, path); - if (result.ok) { - const cooked: Array<WorkspaceHistoryEntryStat> = []; - for (const [name, stat] of result.value) { - stat.created = DateTime.fromSeconds(stat.created as any as number); - stat.updated = DateTime.fromSeconds(stat.updated as any as number); - if (stat.tag === WorkspaceHistory2EntryStatTag.File) { - (stat as WorkspaceHistoryEntryStatFile).isFile = (): boolean => true; - (stat as WorkspaceHistoryEntryStatFile).name = name; - (stat as WorkspaceHistoryEntryStatFile).path = await Path.join(path, name); - } else { - (stat as WorkspaceHistoryEntryStatFolder).isFile = (): boolean => false; - (stat as WorkspaceHistoryEntryStatFolder).name = name; - (stat as WorkspaceHistoryEntryStatFolder).path = await Path.join(path, name); - } - cooked.push(stat as WorkspaceHistoryEntryStat); + const result = await libparsec.workspaceHistory2StatFolderChildren(this.handle, path); + if (result.ok) { + const cooked: Array<WorkspaceHistoryEntryStat> = []; + for (const [name, stat] of result.value) { + stat.created = DateTime.fromSeconds(stat.created as any as number); + stat.updated = DateTime.fromSeconds(stat.updated as any as number); + if (stat.tag === WorkspaceHistory2EntryStatTag.File) { + (stat as WorkspaceHistoryEntryStatFile).isFile = (): boolean => true; + (stat as WorkspaceHistoryEntryStatFile).name = name; + (stat as WorkspaceHistoryEntryStatFile).path = await Path.join(path, name); + } else { + (stat as WorkspaceHistoryEntryStatFolder).isFile = (): boolean => false; + (stat as WorkspaceHistoryEntryStatFolder).name = name; + (stat as WorkspaceHistoryEntryStatFolder).path = await Path.join(path, name); } - return { ok: true, value: cooked }; + cooked.push(stat as WorkspaceHistoryEntryStat); } - return result; + return { ok: true, value: cooked }; } - // Take some time to load - await wait(1500); - const items = (await generateEntriesForEachFileType(path)).map((entry) => { - return entry as any as WorkspaceHistoryEntryStat; - }); - return { ok: true, value: items }; + return result; } async entryStat(path: FsPath): Promise<Result<WorkspaceHistoryEntryStat, WorkspaceHistory2StatEntryError>> { @@ -200,108 +153,41 @@ export class WorkspaceHistory { } const fileName = (await Path.filename(path)) || ''; - - if (!needsMocks()) { - const result = await libparsec.workspaceHistory2StatEntry(this.handle, path); - if (result.ok) { - if (result.value.tag === WorkspaceHistory2EntryStatTag.File) { - (result.value as WorkspaceHistoryEntryStatFile).isFile = (): boolean => true; - (result.value as WorkspaceHistoryEntryStatFile).name = fileName; - (result.value as WorkspaceHistoryEntryStatFile).path = path; - } else { - (result.value as WorkspaceHistoryEntryStatFolder).isFile = (): boolean => false; - (result.value as WorkspaceHistoryEntryStatFolder).name = fileName; - (result.value as WorkspaceHistoryEntryStatFolder).path = path; - } - return result as Result<WorkspaceHistoryEntryStat, WorkspaceHistory2StatEntryError>; + const result = await libparsec.workspaceHistory2StatEntry(this.handle, path); + if (result.ok) { + if (result.value.tag === WorkspaceHistory2EntryStatTag.File) { + (result.value as WorkspaceHistoryEntryStatFile).isFile = (): boolean => true; + (result.value as WorkspaceHistoryEntryStatFile).name = fileName; + (result.value as WorkspaceHistoryEntryStatFile).path = path; + } else { + (result.value as WorkspaceHistoryEntryStatFolder).isFile = (): boolean => false; + (result.value as WorkspaceHistoryEntryStatFolder).name = fileName; + (result.value as WorkspaceHistoryEntryStatFolder).path = path; } - return result; + return result as Result<WorkspaceHistoryEntryStat, WorkspaceHistory2StatEntryError>; } - const entry = fileName.startsWith('File_') ? await generateFile(path, { fileName: fileName }) : await generateFolder(path); - return { ok: true, value: entry as any as WorkspaceHistoryEntryStat }; + return result; } async openFile(path: FsPath): Promise<Result<FileDescriptor, WorkspaceHistory2OpenFileError>> { if (this.handle === undefined) { return { ok: false, error: { tag: WorkspaceHistory2OpenFileErrorTag.Internal, error: 'Not started' } }; } - if (!needsMocks()) { - const result = await libparsec.workspaceHistory2OpenFile(this.handle, path); - return result; - } else { - const fd = MOCK_CURRENT_FD; - MOCK_CURRENT_FD += 1; - MOCK_OPENED_FILES.set(fd, path); - return { ok: true, value: fd }; - } + return await libparsec.workspaceHistory2OpenFile(this.handle, path); } async closeFile(fd: FileDescriptor): Promise<Result<null, WorkspaceHistory2FdCloseError>> { if (this.handle === undefined) { return { ok: false, error: { tag: WorkspaceHistory2FdCloseErrorTag.Internal, error: 'Not started' } }; } - if (!needsMocks()) { - return await libparsec.workspaceHistory2FdClose(this.handle, fd); - } else { - if (!MOCK_OPENED_FILES.has(fd)) { - return { ok: false, error: { tag: WorkspaceHistory2FdCloseErrorTag.BadFileDescriptor, error: 'Invalid file descriptor' } }; - } - MOCK_OPENED_FILES.delete(fd); - return { ok: true, value: null }; - } + return await libparsec.workspaceHistory2FdClose(this.handle, fd); } async readFile(fd: FileDescriptor, offset: number, size: number): Promise<Result<Uint8Array, WorkspaceHistory2FdReadError>> { if (this.handle === undefined) { return { ok: false, error: { tag: WorkspaceHistory2FdReadErrorTag.Internal, error: 'Not started' } }; } - if (!needsMocks()) { - return await libparsec.workspaceHistory2FdRead(this.handle, fd, offset, size); - } else { - if (!MOCK_OPENED_FILES.has(fd)) { - return { ok: false, error: { tag: WorkspaceHistory2FdReadErrorTag.BadFileDescriptor, error: 'Invalid file descriptor' } }; - } - await wait(100); - const path = MOCK_OPENED_FILES.get(fd) as string; - const fileName = (await Path.filename(path)) as EntryName; - const ext = Path.getFileExtension(fileName); - - switch (ext) { - case 'xlsx': - offset === 0 && console.log('Using XLSX content'); - return { ok: true, value: (await getMockFileContent(MockFileType.XLSX)).slice(offset, offset + size) }; - case 'png': - offset === 0 && console.log('Using PNG content'); - return { ok: true, value: (await getMockFileContent(MockFileType.PNG)).slice(offset, offset + size) }; - case 'docx': - offset === 0 && console.log('Using DOCX content'); - return { ok: true, value: (await getMockFileContent(MockFileType.DOCX)).slice(offset, offset + size) }; - case 'txt': - offset === 0 && console.log('Using TXT content'); - return { ok: true, value: (await getMockFileContent(MockFileType.TXT)).slice(offset, offset + size) }; - case 'py': - offset === 0 && console.log('Using PY content'); - return { ok: true, value: (await getMockFileContent(MockFileType.PY)).slice(offset, offset + size) }; - case 'pdf': - offset === 0 && console.log('Using PDF content'); - return { ok: true, value: (await getMockFileContent(MockFileType.PDF)).slice(offset, offset + size) }; - case 'mp3': - offset === 0 && console.log('Using MP3 content'); - return { ok: true, value: (await getMockFileContent(MockFileType.MP3)).slice(offset, offset + size) }; - case 'mp4': - offset === 0 && console.log('Using MP4 content'); - return { ok: true, value: (await getMockFileContent(MockFileType.MP4)).slice(offset, offset + size) }; - } - offset === 0 && console.log('Using default file content'); - return { - ok: true, - value: new Uint8Array([ - 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 5, 0, 0, 0, 5, 8, 6, 0, 0, 0, 141, 111, 38, 229, 0, 0, 0, - 28, 73, 68, 65, 84, 8, 215, 99, 248, 255, 255, 63, 195, 127, 6, 32, 5, 195, 32, 18, 132, 208, 49, 241, 130, 88, 205, 4, 0, 14, - 245, 53, 203, 209, 142, 14, 31, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130, - ]), - }; - } + return await libparsec.workspaceHistory2FdRead(this.handle, fd, BigInt(offset), BigInt(size)); } } @@ -343,7 +229,7 @@ export async function listTreeAt(history: WorkspaceHistory, path: FsPath, depthL tree.maxFilesReached = true; } } else { - tree.totalSize += (entry as WorkspaceHistoryEntryStatFile).size; + tree.totalSize += Number((entry as WorkspaceHistoryEntryStatFile).size); tree.entries.push(entry as WorkspaceHistoryEntryStatFile); if (tree.entries.length > filesLimit) { tree.maxFilesReached = true; diff --git a/client/src/parsec/invitation.ts b/client/src/parsec/invitation.ts index 37a43d3e342..5ab83227b6c 100644 --- a/client/src/parsec/invitation.ts +++ b/client/src/parsec/invitation.ts @@ -1,15 +1,11 @@ // Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS -import { needsMocks } from '@/parsec/environment'; import { getClientInfo } from '@/parsec/login'; import { getParsecHandle } from '@/parsec/routing'; import { ClientCancelInvitationError, ClientInfo, - ClientNewDeviceInvitationError, ClientNewUserInvitationError, - ClientNewUserInvitationErrorTag, - InvitationEmailSentStatus, InvitationStatus, InvitationToken, InviteListInvitationCreatedByTag, @@ -20,54 +16,17 @@ import { Result, UserInvitation, } from '@/parsec/types'; -import { listUsers } from '@/parsec/user'; +import { generateNoHandleError } from '@/parsec/utils'; import { libparsec } from '@/plugins/libparsec'; import { DateTime } from 'luxon'; export async function inviteUser(email: string): Promise<Result<NewInvitationInfo, ClientNewUserInvitationError>> { const handle = getParsecHandle(); - if (handle !== null && !needsMocks()) { + if (handle !== null) { return await libparsec.clientNewUserInvitation(handle, email, true); - } else { - const usersResult = await listUsers(true); - if (usersResult.ok) { - if (usersResult.value.map((u) => u.humanHandle.email).includes(email)) { - return { - ok: false, - error: { - tag: ClientNewUserInvitationErrorTag.AlreadyMember, - error: `${email} is already a member of this organization`, - }, - }; - } - } - return { - ok: true, - value: { - token: '12346565645645654645645645645645', - emailSentStatus: InvitationEmailSentStatus.Success, - // cspell:disable-next-line - addr: 'parsec3://parsec.example.com/Org?a=claimer_user&p=xBjXbfjrnrnrjnrjnrnjrjnrjnrjnrjnrjk', - }, - }; - } -} - -export async function inviteDevice( - sendEmail: boolean, -): Promise<Result<[InvitationToken, InvitationEmailSentStatus], ClientNewDeviceInvitationError>> { - const handle = getParsecHandle(); - - if (handle !== null && !needsMocks()) { - const ret = await libparsec.clientNewDeviceInvitation(handle, sendEmail); - if (ret.ok) { - return { ok: true, value: [ret.value.token, ret.value.emailSentStatus] }; - } else { - return ret; - } } - return { ok: true, value: ['1234', InvitationEmailSentStatus.Success] }; + return generateNoHandleError<ClientNewUserInvitationError>(); } export async function listUserInvitations(options?: { @@ -102,7 +61,7 @@ export async function listUserInvitations(options?: { const handle = getParsecHandle(); const infoResult = await getClientInfo(); - if (handle !== null && !needsMocks()) { + if (handle !== null) { const result = await libparsec.clientListInvitations(handle); if (!result.ok) { @@ -119,57 +78,15 @@ export async function listUserInvitations(options?: { return item; }); return result as any; - } else { - return { - ok: true, - value: [ - { - tag: InviteListItemTag.User, - // cspell:disable-next-line - addr: 'parsec3://parsec.example.com/MyOrg?a=claim_device&token=xBjXbfjrnrnrjnrjnrnjrjnrjnrjnrjnrjk', - token: '12346565645645654645645645645645', - createdOn: DateTime.now(), - claimerEmail: 'shadowheart@swordcoast.faerun', - createdBy: { - tag: InviteListInvitationCreatedByTag.User, - humanHandle: { - email: 'gale@waterdeep.faerun', - // cspell:disable-next-line - label: 'Gale Dekarios', - }, - userId: '1234', - }, - status: InvitationStatus.Pending, - }, - { - tag: InviteListItemTag.User, - // cspell:disable-next-line - addr: 'parsec3://parsec.example.com/MyOrg?a=claim_user&token=xBjfbfjrnrnrjnrjnrnjrjnrjnrjnrjnrjk', - token: '32346565645645654645645645645645', - createdOn: DateTime.now(), - createdBy: { - tag: InviteListInvitationCreatedByTag.User, - humanHandle: { - email: 'gale@waterdeep.faerun', - // cspell:disable-next-line - label: 'Gale Dekarios', - }, - userId: '1234', - }, - claimerEmail: 'gale@waterdeep.faerun', - status: InvitationStatus.Pending, - }, - ], - }; } + return generateNoHandleError<ListInvitationsError>(); } export async function cancelInvitation(token: InvitationToken): Promise<Result<null, ClientCancelInvitationError>> { const handle = getParsecHandle(); - if (handle !== null && !needsMocks()) { + if (handle !== null) { return await libparsec.clientCancelInvitation(handle, token); - } else { - return { ok: true, value: null }; } + return generateNoHandleError<ClientCancelInvitationError>(); } diff --git a/client/src/parsec/login.ts b/client/src/parsec/login.ts index d54ff5429b8..9db1f7793c7 100644 --- a/client/src/parsec/login.ts +++ b/client/src/parsec/login.ts @@ -1,22 +1,13 @@ // Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS -import { - ActiveUsersLimitTag, - DeviceAccessStrategyKeyring, - DeviceFileType, - DeviceSaveStrategyKeyring, - DeviceSaveStrategyPassword, - libparsec, -} from '@/plugins/libparsec'; - -import { needsMocks } from '@/parsec/environment'; -import { DEFAULT_HANDLE, getClientConfig } from '@/parsec/internals'; +import { DeviceAccessStrategyKeyring, DeviceSaveStrategyKeyring, DeviceSaveStrategyPassword, libparsec } from '@/plugins/libparsec'; + +import { getClientConfig } from '@/parsec/internals'; import { parseParsecAddr } from '@/parsec/organization'; import { getParsecHandle } from '@/parsec/routing'; import { AvailableDevice, ClientChangeAuthenticationError, - ClientChangeAuthenticationErrorTag, ClientEvent, ClientEventGreetingAttemptCancelled, ClientEventGreetingAttemptJoined, @@ -26,7 +17,6 @@ import { ClientInfo, ClientInfoError, ClientStartError, - ClientStartErrorTag, ClientStopError, ConnectionHandle, DeviceAccessStrategy, @@ -38,6 +28,7 @@ import { Result, UserProfile, } from '@/parsec/types'; +import { generateNoHandleError } from '@/parsec/utils'; import { getConnectionHandle } from '@/router'; import { EventDistributor, Events } from '@/services/eventDistributor'; import { DateTime } from 'luxon'; @@ -52,32 +43,6 @@ export interface LoggedInDeviceInfo { const loggedInDevices: Array<LoggedInDeviceInfo> = []; -export function mockLoggedInDevice(): void { - if (loggedInDevices.length === 0) { - loggedInDevices.push({ - handle: DEFAULT_HANDLE, - device: { - keyFilePath: '/fake', - createdOn: DateTime.now(), - protectedOn: DateTime.now(), - serverUrl: 'parsec3://127.0.0.1:6770?no_ssl=true', - organizationId: 'MyOrg', - userId: 'MockUserId', - deviceId: 'MockDeviceId', - humanHandle: { - label: 'Gordon Freeman', - email: 'gordon.freeman@blackmesa.nm', - }, - deviceLabel: 'HEV Suit', - ty: DeviceFileType.Password, - }, - isExpired: false, - isOnline: true, - shouldAcceptTos: false, - }); - } -} - export async function getLoggedInDevices(): Promise<Array<LoggedInDeviceInfo>> { return loggedInDevices; } @@ -98,15 +63,6 @@ export function getConnectionInfo(handle: ConnectionHandle | null = null): Logge if (!handle) { handle = getParsecHandle(); } - if (needsMocks()) { - return { - handle: DEFAULT_HANDLE, - device: {} as AvailableDevice, - isExpired: false, - isOnline: true, - shouldAcceptTos: false, - }; - } return loggedInDevices.find((info) => info.handle === handle); } @@ -268,30 +224,12 @@ export async function login( const callback = (handle: ConnectionHandle, event: ClientEvent): void => { parsecEventCallback(eventDistributor, event, handle); }; - if (!needsMocks()) { - const clientConfig = getClientConfig(); - const result = await libparsec.clientStart(clientConfig, callback, accessStrategy); - if (result.ok) { - loggedInDevices.push({ handle: result.value, device: device, isExpired: false, isOnline: false, shouldAcceptTos: false }); - } - return result; - } else { - if ( - accessStrategy.tag === DeviceAccessStrategyTag.Password && - ['P@ssw0rd.', 'AVeryL0ngP@ssw0rd'].includes((accessStrategy as DeviceAccessStrategyPassword).password) - ) { - loggedInDevices.push({ handle: DEFAULT_HANDLE, device: device, isExpired: false, isOnline: true, shouldAcceptTos: false }); - callback(DEFAULT_HANDLE, { tag: ClientEventTag.Online }); - return { ok: true, value: DEFAULT_HANDLE }; - } - return { - ok: false, - error: { - tag: ClientStartErrorTag.LoadDeviceDecryptionFailed, - error: 'WrongPassword', - }, - }; + const clientConfig = getClientConfig(); + const result = await libparsec.clientStart(clientConfig, callback, accessStrategy); + if (result.ok) { + loggedInDevices.push({ handle: result.value, device: device, isExpired: false, isOnline: false, shouldAcceptTos: false }); } + return result; } export async function logout(handle?: ConnectionHandle | undefined | null): Promise<Result<null, ClientStopError>> { @@ -299,7 +237,7 @@ export async function logout(handle?: ConnectionHandle | undefined | null): Prom handle = getParsecHandle(); } - if (handle !== null && !needsMocks()) { + if (handle !== null) { const result = await libparsec.clientStop(handle); if (result.ok) { const index = loggedInDevices.findIndex((info) => info.handle === handle); @@ -308,13 +246,8 @@ export async function logout(handle?: ConnectionHandle | undefined | null): Prom } } return result; - } else { - const index = loggedInDevices.findIndex((info) => info.handle === handle); - if (index !== -1) { - loggedInDevices.splice(index, 1); - } - return { ok: true, value: null }; } + return generateNoHandleError<ClientStopError>(); } export async function getClientInfo(handle: ConnectionHandle | null = null): Promise<Result<ClientInfo, ClientInfoError>> { @@ -322,31 +255,10 @@ export async function getClientInfo(handle: ConnectionHandle | null = null): Pro handle = getConnectionHandle(); } - if (handle !== null && !needsMocks()) { + if (handle !== null) { return await libparsec.clientInfo(handle); - } else { - return { - ok: true, - value: { - organizationAddr: 'parsec3://example.com/MyOrg', - organizationId: 'MyOrg', - deviceId: 'device1', - deviceLabel: 'My First Device', - userId: 'me', - currentProfile: UserProfile.Admin, - humanHandle: { - email: 'user@host.com', - label: 'Gordon Freeman', - }, - serverConfig: { - userProfileOutsiderAllowed: true, - activeUsersLimit: { - tag: ActiveUsersLimitTag.NoLimit, - }, - }, - }, - }; } + return generateNoHandleError<ClientInfoError>(); } export async function getClientProfile(): Promise<UserProfile> { @@ -379,40 +291,20 @@ export async function getCurrentAvailableDevice(): Promise<Result<AvailableDevic return { ok: false, error: { tag: 'NotFound' } }; } const availableDevices = await listAvailableDevices(); - // clientInfo are not real on web right now - // const currentAvailableDevice = availableDevices.find((device) => device.deviceId === clientResult.value.deviceId); - if (!needsMocks()) { - const currentAvailableDevice = availableDevices.find((device) => device.deviceId === clientResult.value.deviceId); - if (!currentAvailableDevice) { - return { ok: false, error: { tag: 'NotFound' } }; - } - return { ok: true, value: currentAvailableDevice }; - } else { - const device = availableDevices[0]; - // Uncomment this to experience the login as you would with keyring - // device.ty = DeviceFileType.Keyring; - return { ok: true, value: device }; + const currentAvailableDevice = availableDevices.find((device) => device.deviceId === clientResult.value.deviceId); + if (!currentAvailableDevice) { + return { ok: false, error: { tag: 'NotFound' } }; } + return { ok: true, value: currentAvailableDevice }; } export async function changeAuthentication( accessStrategy: DeviceAccessStrategy, saveStrategy: DeviceSaveStrategy, ): Promise<Result<null, ClientChangeAuthenticationError>> { - if (!needsMocks()) { - const clientConfig = getClientConfig(); - return await libparsec.clientChangeAuthentication(clientConfig, accessStrategy, saveStrategy); - } else { - // Fake an error - if ( - accessStrategy.tag === DeviceAccessStrategyTag.Password && - (accessStrategy as DeviceAccessStrategyPassword).password !== 'P@ssw0rd.' - ) { - return { ok: false, error: { tag: ClientChangeAuthenticationErrorTag.DecryptionFailed, error: 'Invalid password' } }; - } - return { ok: true, value: null }; - } + const clientConfig = getClientConfig(); + return await libparsec.clientChangeAuthentication(clientConfig, accessStrategy, saveStrategy); } export async function isKeyringAvailable(): Promise<boolean> { @@ -450,14 +342,7 @@ export const SaveStrategy = { }; export async function isAuthenticationValid(device: AvailableDevice, accessStrategy: DeviceAccessStrategy): Promise<boolean> { - if (!needsMocks()) { - const clientConfig = getClientConfig(); - const result = await libparsec.clientStart(clientConfig, (_handle: number, _event: ClientEvent) => {}, accessStrategy); - return result.ok; - } else { - return ( - accessStrategy.tag === DeviceAccessStrategyTag.Password && - ['P@ssw0rd.', 'AVeryL0ngP@ssw0rd'].includes((accessStrategy as DeviceAccessStrategyPassword).password) - ); - } + const clientConfig = getClientConfig(); + const result = await libparsec.clientStart(clientConfig, (_handle: number, _event: ClientEvent) => {}, accessStrategy); + return result.ok; } diff --git a/client/src/parsec/organization.ts b/client/src/parsec/organization.ts index 1b8f398d73f..e754d8f5b8f 100644 --- a/client/src/parsec/organization.ts +++ b/client/src/parsec/organization.ts @@ -8,8 +8,6 @@ import { libparsec, } from '@/plugins/libparsec'; -import { needsMocks } from '@/parsec/environment'; -import { MOCK_WAITING_TIME, wait } from '@/parsec/internals'; import { getClientInfo } from '@/parsec/login'; import { AvailableDevice, @@ -17,7 +15,6 @@ import { BootstrapOrganizationErrorTag, ClientConfig, ClientEvent, - DeviceFileType, DeviceSaveStrategy, OrganizationID, OrganizationInfo, @@ -46,53 +43,33 @@ export async function createOrganization( const bootstrapAddr = await libparsec.buildParsecOrganizationBootstrapAddr(serverAddr, orgName); - if (!needsMocks()) { - const config: ClientConfig = { - configDir: window.getConfigDir(), - dataBaseDir: window.getDataBaseDir(), - mountpointMountStrategy: { tag: MountpointMountStrategyTag.Disabled }, - workspaceStorageCacheSize: { tag: WorkspaceStorageCacheSizeTag.Default }, - withMonitors: false, - preventSyncPattern: null, - }; - const result = await libparsec.bootstrapOrganization( - config, - parsecEventCallback, - bootstrapAddr, - saveStrategy, - { label: userName, email: email }, - deviceLabel, - null, - ); - if (!result.ok && result.error.tag === BootstrapOrganizationErrorTag.TimestampOutOfBallpark) { - result.error.clientTimestamp = DateTime.fromSeconds(result.error.clientTimestamp as any as number); - result.error.serverTimestamp = DateTime.fromSeconds(result.error.serverTimestamp as any as number); - } else if (result.ok) { - result.value.createdOn = DateTime.fromSeconds(result.value.createdOn as any as number); - result.value.protectedOn = DateTime.fromSeconds(result.value.protectedOn as any as number); - } - return result; - } else { - await wait(MOCK_WAITING_TIME); - return { - ok: true, - value: { - keyFilePath: '/path', - serverUrl: 'https://parsec.invalid', - createdOn: DateTime.utc(), - protectedOn: DateTime.utc(), - organizationId: 'MyOrg', - userId: 'userid', - deviceId: 'deviceid', - humanHandle: { - label: 'A', - email: 'a@b.c', - }, - deviceLabel: 'a@b', - ty: DeviceFileType.Password, - }, - }; + console.log(bootstrapAddr); + + const config: ClientConfig = { + configDir: window.getConfigDir(), + dataBaseDir: window.getDataBaseDir(), + mountpointMountStrategy: { tag: MountpointMountStrategyTag.Disabled }, + workspaceStorageCacheSize: { tag: WorkspaceStorageCacheSizeTag.Default }, + withMonitors: false, + preventSyncPattern: null, + }; + const result = await libparsec.bootstrapOrganization( + config, + parsecEventCallback, + bootstrapAddr, + saveStrategy, + { label: userName, email: email }, + deviceLabel, + null, + ); + if (!result.ok && result.error.tag === BootstrapOrganizationErrorTag.TimestampOutOfBallpark) { + result.error.clientTimestamp = DateTime.fromSeconds(result.error.clientTimestamp as any as number); + result.error.serverTimestamp = DateTime.fromSeconds(result.error.serverTimestamp as any as number); + } else if (result.ok) { + result.value.createdOn = DateTime.fromSeconds(result.value.createdOn as any as number); + result.value.protectedOn = DateTime.fromSeconds(result.value.protectedOn as any as number); } + return result; } export async function bootstrapOrganization( @@ -106,53 +83,31 @@ export async function bootstrapOrganization( console.log('On event', event); } - if (!needsMocks()) { - const config: ClientConfig = { - configDir: window.getConfigDir(), - dataBaseDir: window.getDataBaseDir(), - mountpointMountStrategy: { tag: MountpointMountStrategyTag.Disabled }, - workspaceStorageCacheSize: { tag: WorkspaceStorageCacheSizeTag.Default }, - withMonitors: false, - preventSyncPattern: null, - }; - const result = await libparsec.bootstrapOrganization( - config, - parsecEventCallback, - bootstrapAddr, - saveStrategy, - { label: userName, email: email }, - deviceLabel, - null, - ); - if (!result.ok && result.error.tag === BootstrapOrganizationErrorTag.TimestampOutOfBallpark) { - result.error.clientTimestamp = DateTime.fromSeconds(result.error.clientTimestamp as any as number); - result.error.serverTimestamp = DateTime.fromSeconds(result.error.serverTimestamp as any as number); - } else if (result.ok) { - result.value.createdOn = DateTime.fromSeconds(result.value.createdOn as any as number); - result.value.protectedOn = DateTime.fromSeconds(result.value.protectedOn as any as number); - } - return result; - } else { - await wait(MOCK_WAITING_TIME); - return { - ok: true, - value: { - keyFilePath: '/path', - serverUrl: 'https://parsec.invalid', - createdOn: DateTime.utc(), - protectedOn: DateTime.utc(), - organizationId: 'MyOrg', - userId: 'userid', - deviceId: 'deviceid', - humanHandle: { - label: 'A', - email: 'a@b.c', - }, - deviceLabel: 'a@b', - ty: DeviceFileType.Password, - }, - }; + const config: ClientConfig = { + configDir: window.getConfigDir(), + dataBaseDir: window.getDataBaseDir(), + mountpointMountStrategy: { tag: MountpointMountStrategyTag.Disabled }, + workspaceStorageCacheSize: { tag: WorkspaceStorageCacheSizeTag.Default }, + withMonitors: false, + preventSyncPattern: null, + }; + const result = await libparsec.bootstrapOrganization( + config, + parsecEventCallback, + bootstrapAddr, + saveStrategy, + { label: userName, email: email }, + deviceLabel, + null, + ); + if (!result.ok && result.error.tag === BootstrapOrganizationErrorTag.TimestampOutOfBallpark) { + result.error.clientTimestamp = DateTime.fromSeconds(result.error.clientTimestamp as any as number); + result.error.serverTimestamp = DateTime.fromSeconds(result.error.serverTimestamp as any as number); + } else if (result.ok) { + result.value.createdOn = DateTime.fromSeconds(result.value.createdOn as any as number); + result.value.protectedOn = DateTime.fromSeconds(result.value.protectedOn as any as number); } + return result; } export async function parseParsecAddr(addr: string): Promise<Result<ParsedParsecAddr, ParseParsecAddrError>> { @@ -185,7 +140,7 @@ export async function getOrganizationInfo(): Promise<Result<OrganizationInfo, Or outsidersAllowed: clientInfoResult.value.serverConfig.userProfileOutsiderAllowed, userLimit: clientInfoResult.value.serverConfig.activeUsersLimit.tag === ActiveUsersLimitTag.LimitedTo - ? (clientInfoResult.value.serverConfig.activeUsersLimit as ActiveUsersLimitLimitedTo).x1 + ? Number((clientInfoResult.value.serverConfig.activeUsersLimit as ActiveUsersLimitLimitedTo).x1) : undefined, hasUserLimit: clientInfoResult.value.serverConfig.activeUsersLimit.tag !== ActiveUsersLimitTag.NoLimit, organizationAddr: clientInfoResult.value.organizationAddr, diff --git a/client/src/parsec/terms_of_service.ts b/client/src/parsec/terms_of_service.ts index c56ea9237f5..34952ab04e2 100644 --- a/client/src/parsec/terms_of_service.ts +++ b/client/src/parsec/terms_of_service.ts @@ -1,40 +1,29 @@ // Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS -import { needsMocks } from '@/parsec/environment'; import { getParsecHandle } from '@/parsec/routing'; import { ClientAcceptTosError, ClientGetTosError, Result, Tos } from '@/parsec/types'; +import { generateNoHandleError } from '@/parsec/utils'; import { libparsec } from '@/plugins/libparsec'; import { DateTime } from 'luxon'; export async function acceptTOS(updatedOn: DateTime): Promise<Result<null, ClientAcceptTosError>> { const handle = getParsecHandle(); - if (handle !== null && !needsMocks()) { + if (handle !== null) { return await libparsec.clientAcceptTos(handle, updatedOn.toSeconds() as any as DateTime); - } else { - return { ok: true, value: null }; } + return generateNoHandleError<ClientAcceptTosError>(); } export async function getTOS(): Promise<Result<Tos, ClientGetTosError>> { const handle = getParsecHandle(); - if (handle !== null && !needsMocks()) { + if (handle !== null) { const result = await libparsec.clientGetTos(handle); if (result.ok) { result.value.updatedOn = DateTime.fromSeconds(result.value.updatedOn as any as number); } return result; - } else { - return { - ok: true, - value: { - perLocaleUrls: new Map<string, string>([ - ['en-US', 'https://parsec.cloud/en/404'], - ['fr-FR', 'https://parsec.cloud/404'], - ]), - updatedOn: DateTime.now(), - }, - }; } + return generateNoHandleError<ClientGetTosError>(); } diff --git a/client/src/parsec/user.ts b/client/src/parsec/user.ts index 0df19f8acc8..d6b8b941a80 100644 --- a/client/src/parsec/user.ts +++ b/client/src/parsec/user.ts @@ -2,7 +2,6 @@ import { libparsec } from '@/plugins/libparsec'; -import { needsMocks } from '@/parsec/environment'; import { getParsecHandle } from '@/parsec/routing'; import { ClientListUsersError, @@ -13,6 +12,7 @@ import { UserInfo, UserProfile, } from '@/parsec/types'; +import { generateNoHandleError } from '@/parsec/utils'; import { DateTime } from 'luxon'; function filterUserList(list: Array<UserInfo>, pattern: string): Array<UserInfo> { @@ -25,7 +25,7 @@ function filterUserList(list: Array<UserInfo>, pattern: string): Array<UserInfo> export async function listUsers(skipRevoked = true, pattern = ''): Promise<Result<Array<UserInfo>, ClientListUsersError>> { const handle = getParsecHandle(); - if (handle !== null && !needsMocks()) { + if (handle !== null) { const result = await libparsec.clientListUsers(handle, skipRevoked); if (result.ok) { const frozenResult = await libparsec.clientListFrozenUsers(handle); @@ -47,134 +47,17 @@ export async function listUsers(skipRevoked = true, pattern = ''): Promise<Resul }); } return result as any as Promise<Result<Array<UserInfo>, ClientListUsersError>>; - } else { - let value: Array<UserInfo> = [ - { - id: 'me', - humanHandle: { - email: 'user@host.com', - label: 'Gordon Freeman', - }, - currentProfile: UserProfile.Admin, - createdOn: DateTime.now(), - createdBy: 'device', - revokedOn: null, - revokedBy: null, - isRevoked: (): boolean => false, - isFrozen: (): boolean => false, - isActive: (): boolean => true, - }, - { - id: '0123456789abcdef012345689abcdef', - // cspell:disable-next-line - humanHandle: { label: 'Cernd', email: 'cernd@gmail.com' }, - currentProfile: UserProfile.Standard, - createdOn: DateTime.now(), - createdBy: 'device', - revokedOn: null, - revokedBy: null, - isRevoked: (): boolean => false, - isFrozen: (): boolean => false, - isActive: (): boolean => true, - }, - { - id: '123456789abcdef012345689abcdef0', - // cspell:disable-next-line - humanHandle: { label: 'Jaheira', email: 'jaheira@gmail.com' }, - currentProfile: UserProfile.Admin, - createdOn: DateTime.now(), - createdBy: 'device', - revokedOn: null, - revokedBy: null, - isRevoked: (): boolean => false, - isFrozen: (): boolean => false, - isActive: (): boolean => true, - }, - { - id: '23456789abcdef012345689abcdef01', - // cspell:disable-next-line - humanHandle: { label: 'Karl Hungus', email: 'karlhungus@gmail.com' }, - currentProfile: UserProfile.Outsider, - createdOn: DateTime.utc(1998, 4, 22), - createdBy: 'device', - revokedOn: null, - revokedBy: null, - isRevoked: (): boolean => false, - isFrozen: (): boolean => true, - isActive: (): boolean => false, - }, - { - id: '3456789abcdef012345689abcdef012', - // cspell:disable-next-line - humanHandle: { label: 'Patches', email: 'patches@yahoo.fr' }, - currentProfile: UserProfile.Standard, - createdOn: DateTime.utc(2009, 10, 6), - createdBy: 'device', - revokedOn: null, - revokedBy: null, - isRevoked: (): boolean => false, - isFrozen: (): boolean => false, - isActive: (): boolean => true, - }, - ]; - if (!skipRevoked) { - value.push( - { - id: '456789abcdef012345689abcdef0123', - // cspell:disable-next-line - humanHandle: { label: 'Arthas Menethil', email: 'arthasmenethil@gmail.com' }, - currentProfile: UserProfile.Admin, - createdOn: DateTime.utc(2002, 7, 3), - createdBy: 'device', - revokedOn: DateTime.utc(2022, 4, 7), - revokedBy: 'device', - isRevoked: (): boolean => true, - isFrozen: (): boolean => false, - isActive: (): boolean => false, - }, - { - id: '56789abcdef012345689abcdef01234', - // cspell:disable-next-line - humanHandle: { label: 'Gaia', email: 'gaia@gmail.com' }, - currentProfile: UserProfile.Outsider, - createdOn: DateTime.utc(2019, 7, 16), - createdBy: 'device', - revokedOn: DateTime.utc(2023, 11, 3), - revokedBy: 'device', - isRevoked: (): boolean => true, - isFrozen: (): boolean => false, - isActive: (): boolean => false, - }, - { - id: '6789abcdef012345689abcdef012345', - // cspell:disable-next-line - humanHandle: { label: 'Valygar Corthala', email: 'val@gmail.com' }, - currentProfile: UserProfile.Standard, - createdOn: DateTime.utc(2015, 2, 17), - createdBy: 'device', - revokedOn: DateTime.utc(2024, 5, 18), - revokedBy: 'device', - isRevoked: (): boolean => true, - isFrozen: (): boolean => false, - isActive: (): boolean => false, - }, - ); - } - if (pattern.length > 0) { - value = filterUserList(value, pattern); - } - return { ok: true, value: value }; } + return generateNoHandleError<ClientListUsersError>(); } export async function revokeUser(userId: UserID): Promise<Result<null, ClientRevokeUserError>> { const handle = getParsecHandle(); - if (handle !== null && !needsMocks()) { + if (handle !== null) { return await libparsec.clientRevokeUser(handle, userId); - } else { - return { ok: true, value: null }; } + return generateNoHandleError<ClientRevokeUserError>(); } export enum UserInfoErrorTag { @@ -209,9 +92,8 @@ export async function getUserInfo(userId: UserID): Promise<Result<UserInfo, User export async function updateProfile(userId: UserID, profile: UserProfile): Promise<Result<null, ClientUserUpdateProfileError>> { const handle = getParsecHandle(); - if (handle !== null && !needsMocks()) { + if (handle !== null) { return await libparsec.clientUpdateUserProfile(handle, userId, profile); - } else { - return { ok: true, value: null }; } + return generateNoHandleError<ClientUserUpdateProfileError>(); } diff --git a/client/src/parsec/utils.ts b/client/src/parsec/utils.ts new file mode 100644 index 00000000000..09aab789b12 --- /dev/null +++ b/client/src/parsec/utils.ts @@ -0,0 +1,7 @@ +// Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS + +import { Result } from '@/parsec/types'; + +export function generateNoHandleError<T>(): Result<any, T> { + return { ok: false, error: { tag: 'Internal', error: 'No handle' } as any }; +} diff --git a/client/src/parsec/workspace.ts b/client/src/parsec/workspace.ts index 2defadd114b..a62970675f6 100644 --- a/client/src/parsec/workspace.ts +++ b/client/src/parsec/workspace.ts @@ -1,7 +1,6 @@ // Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS import { DataCache } from '@/common/cache'; -import { needsMocks } from '@/parsec/environment'; import { getClientInfo } from '@/parsec/login'; import { getParsecHandle } from '@/parsec/routing'; import { @@ -21,7 +20,6 @@ import { StartedWorkspaceInfo, SystemPath, UserID, - UserProfile, UserTuple, WorkspaceDecryptPathAddrError, WorkspaceGeneratePathAddrError, @@ -29,12 +27,12 @@ import { WorkspaceID, WorkspaceInfo, WorkspaceInfoError, - WorkspaceInfoErrorTag, WorkspaceMountError, WorkspaceMountErrorTag, WorkspaceName, WorkspaceRole, } from '@/parsec/types'; +import { generateNoHandleError } from '@/parsec/utils'; import { WorkspaceStopError, libparsec } from '@/plugins/libparsec'; import { DateTime } from 'luxon'; @@ -75,7 +73,7 @@ export async function listWorkspaces( handle = getParsecHandle(); } - if (handle !== null && !needsMocks()) { + if (handle !== null) { const result = await libparsec.clientListWorkspaces(handle); if (result.ok) { @@ -106,112 +104,24 @@ export async function listWorkspaces( } else { return result; } - } else { - const value: Array<WorkspaceInfo> = [ - { - id: '1', - currentName: 'Trademeet', - currentSelfRole: WorkspaceRole.Owner, - size: 934_583, - lastUpdated: DateTime.now().minus(2000), - availableOffline: false, - isStarted: false, - isBootstrapped: false, - sharing: [], - mountpoints: [[1, '/home/a']], - handle: 1, - }, - { - id: '2', - currentName: 'The Copper Coronet', - currentSelfRole: WorkspaceRole.Contributor, - size: 3_489_534_274, - lastUpdated: DateTime.now(), - availableOffline: false, - isStarted: false, - isBootstrapped: true, - sharing: [], - mountpoints: [[2, '/home/b']], - handle: 2, - }, - { - id: '3', - currentName: "Watcher's Keep", - currentSelfRole: WorkspaceRole.Reader, - size: 56_153_023, - lastUpdated: DateTime.now(), - availableOffline: true, - isStarted: false, - isBootstrapped: true, - sharing: [], - mountpoints: [[3, '/home/c']], - handle: 3, - }, - ]; - - return { ok: true, value: value }; } + return generateNoHandleError<ClientListWorkspacesError>(); } export async function getWorkspaceInfo(workspaceHandle: WorkspaceHandle): Promise<Result<StartedWorkspaceInfo, WorkspaceInfoError>> { - if (!needsMocks()) { - const result = await libparsec.workspaceInfo(workspaceHandle); - if (result.ok) { - (result.value as StartedWorkspaceInfo).handle = workspaceHandle; - const createdResult = await libparsec.workspaceHistoryGetWorkspaceManifestV1Timestamp(workspaceHandle); - if (createdResult.ok && createdResult.value) { - try { - (result.value as StartedWorkspaceInfo).created = DateTime.fromSeconds(createdResult.value as any as number); - } catch (error: any) { - console.error(error); - } + const result = await libparsec.workspaceInfo(workspaceHandle); + if (result.ok) { + (result.value as StartedWorkspaceInfo).handle = workspaceHandle; + const createdResult = await libparsec.workspaceHistoryGetWorkspaceManifestV1Timestamp(workspaceHandle); + if (createdResult.ok && createdResult.value) { + try { + (result.value as StartedWorkspaceInfo).created = DateTime.fromSeconds(createdResult.value as any as number); + } catch (error: any) { + console.error(error); } } - return result as Result<StartedWorkspaceInfo, WorkspaceInfoError>; - } else { - switch (workspaceHandle) { - case 1: - return { - ok: true, - value: { - client: 42, - id: '1', - currentName: 'Trademeet', - currentSelfRole: WorkspaceRole.Owner, - mountpoints: [[1, '/home/a']], - handle: workspaceHandle, - created: DateTime.now().minus({ days: 8 }), - }, - }; - case 2: - return { - ok: true, - value: { - client: 42, - id: '2', - currentName: 'The Copper Coronet', - currentSelfRole: WorkspaceRole.Manager, - mountpoints: [[1, '/home/b']], - handle: workspaceHandle, - created: DateTime.now().minus({ days: 12 }), - }, - }; - case 3: - return { - ok: true, - value: { - client: 42, - id: '3', - currentName: "Watcher's Keep", - currentSelfRole: WorkspaceRole.Reader, - mountpoints: [[1, '/home/c']], - handle: workspaceHandle, - }, - }; - default: - return { ok: false, error: { tag: WorkspaceInfoErrorTag.Internal, error: 'internal' } }; - } } + return result as Result<StartedWorkspaceInfo, WorkspaceInfoError>; } const WORKSPACE_NAMES_CACHE = new DataCache<WorkspaceHandle, string>(); @@ -233,21 +143,19 @@ export async function getWorkspaceName(workspaceHandle: WorkspaceHandle): Promis export async function createWorkspace(name: WorkspaceName): Promise<Result<WorkspaceID, ClientCreateWorkspaceError>> { const handle = getParsecHandle(); - if (handle !== null && !needsMocks()) { + if (handle !== null) { return await libparsec.clientCreateWorkspace(handle, name); - } else { - return { ok: true, value: '1337' }; } + return generateNoHandleError<ClientCreateWorkspaceError>(); } export async function renameWorkspace(newName: WorkspaceName, id: WorkspaceID): Promise<Result<null, ClientRenameWorkspaceError>> { const handle = getParsecHandle(); - if (handle !== null && !needsMocks()) { + if (handle !== null) { return await libparsec.clientRenameWorkspace(handle, id, newName); - } else { - return { ok: true, value: null }; } + return generateNoHandleError<ClientRenameWorkspaceError>(); } export async function getWorkspaceSharing( @@ -257,7 +165,7 @@ export async function getWorkspaceSharing( ): Promise<Result<Array<[UserTuple, WorkspaceRole | null]>, ClientListWorkspaceUsersError>> { const handle = getParsecHandle(); - if (handle !== null && !needsMocks()) { + if (handle !== null) { let selfId: UserID | null = null; if (!includeSelf) { @@ -302,58 +210,9 @@ export async function getWorkspaceSharing( } return { ok: true, value: value }; } - return { ok: false, error: result.error }; - } else { - const value: Array<[UserTuple, WorkspaceRole | null]> = []; - - if (workspaceId === '1' || workspaceId === '2') { - value.push([ - { - id: '0123456789abcdef012345689abcdef', - // cspell:disable-next-line - humanHandle: { label: 'Korgan Bloodaxe', email: 'korgan@gmail.com' }, - profile: UserProfile.Standard, - }, - WorkspaceRole.Reader, - ]); - } - if (workspaceId === '2') { - value.push([ - { - id: '123456789abcdef012345689abcdef0', - // cspell:disable-next-line - humanHandle: { label: 'Cernd', email: 'cernd@gmail.com' }, - profile: UserProfile.Admin, - }, - WorkspaceRole.Contributor, - ]); - } - - if (includeSelf) { - value.push([ - { - id: 'me', - humanHandle: { email: 'user@host.com', label: 'Gordon Freeman' }, - profile: UserProfile.Admin, - }, - WorkspaceRole.Owner, - ]); - } - - if (includeAllUsers) { - value.push([ - { - id: '23456789abcdef012345689abcdef01', - // cspell:disable-next-line - humanHandle: { label: 'Jaheira', email: 'jaheira@gmail.com' }, - profile: UserProfile.Outsider, - }, - null, - ]); - } - - return { ok: true, value: value }; + return result; } + return generateNoHandleError<ClientListWorkspaceUsersError>(); } export async function shareWorkspace( @@ -363,11 +222,10 @@ export async function shareWorkspace( ): Promise<Result<null, ClientShareWorkspaceError>> { const handle = getParsecHandle(); - if (handle !== null && !needsMocks()) { + if (handle !== null) { return await libparsec.clientShareWorkspace(handle, workspaceId, userId, role); - } else { - return { ok: true, value: null }; } + return generateNoHandleError<ClientShareWorkspaceError>(); } export async function startWorkspace( @@ -378,39 +236,34 @@ export async function startWorkspace( connectionHandle = getParsecHandle(); } - if (connectionHandle !== null && !needsMocks()) { + if (connectionHandle !== null) { return await libparsec.clientStartWorkspace(connectionHandle, workspaceId); - } else { - return { ok: true, value: 1337 }; } + return generateNoHandleError<ClientStartWorkspaceError>(); } export async function stopWorkspace(workspaceHandle: WorkspaceHandle): Promise<Result<null, WorkspaceStopError>> { const handle = getParsecHandle(); - if (handle !== null && !needsMocks()) { + if (handle !== null) { return await libparsec.workspaceStop(workspaceHandle); - } else { - return { ok: true, value: null }; } + return generateNoHandleError<WorkspaceStopError>(); } export async function mountWorkspace( workspaceHandle: WorkspaceHandle, ): Promise<Result<[MountpointHandle, SystemPath], WorkspaceMountError>> { - if (!needsMocks()) { - const startedWorkspaceResult = await getWorkspaceInfo(workspaceHandle); - if (!startedWorkspaceResult.ok) { - console.error(`Failed to get started workspace info: ${startedWorkspaceResult.error}`); - return { ok: false, error: { tag: WorkspaceMountErrorTag.Internal, error: '' } }; - } else { - if (startedWorkspaceResult.value.mountpoints.length > 0) { - return { ok: true, value: startedWorkspaceResult.value.mountpoints[0] }; - } + const startedWorkspaceResult = await getWorkspaceInfo(workspaceHandle); + if (!startedWorkspaceResult.ok) { + console.error(`Failed to get started workspace info: ${startedWorkspaceResult.error}`); + return { ok: false, error: { tag: WorkspaceMountErrorTag.Internal, error: '' } }; + } else { + if (startedWorkspaceResult.value.mountpoints.length > 0) { + return { ok: true, value: startedWorkspaceResult.value.mountpoints[0] }; } - return await libparsec.workspaceMount(workspaceHandle); } - return { ok: true, value: [0, ''] }; + return await libparsec.workspaceMount(workspaceHandle); } export async function getPathLink( @@ -418,29 +271,17 @@ export async function getPathLink( path: string, timestamp: DateTime | null = null, ): Promise<Result<ParsecWorkspacePathAddr, WorkspaceGeneratePathAddrError>> { - if (!needsMocks()) { - return await libparsec.workspaceGeneratePathAddr(workspaceHandle, path); + if (timestamp) { + window.electronAPI.log('warn', 'Parameter `timestamp` is ignored'); } - - const org = 'Org'; - // cspell:disable-next-line - const payload = 'k8QY94a350f2f629403db2269c44583f7aa1AcQ0Zkd8YbWfYF19LMwc55HjBOvI8LA8c_9oU2xaBJ0u2Ou0AFZYA4-QHhi2FprzAtUoAgMYwg'; - let link = `parsec3://parsec.cloud/${org}?a=path&p=${payload}`; - if (timestamp !== null) { - // cspell:disable-next-line - link += '×tamp=JEFHNUJEF39350JFHNsss'; - } - return { ok: true, value: link }; + return await libparsec.workspaceGeneratePathAddr(workspaceHandle, path); } export async function decryptFileLink( workspaceHandle: WorkspaceHandle, link: ParsecWorkspacePathAddr, ): Promise<Result<FsPath, WorkspaceDecryptPathAddrError>> { - if (!needsMocks()) { - return await libparsec.workspaceDecryptPathAddr(workspaceHandle, link); - } - return { ok: true, value: '/' }; + return await libparsec.workspaceDecryptPathAddr(workspaceHandle, link); } export interface SharedWithInfo { @@ -491,8 +332,5 @@ export async function getSystemPath( if (infoResult.value.mountpoints.length === 0) { return { ok: false, error: { tag: MountpointToOsPathErrorTag.Internal, error: 'not mounted' } }; } - if (!needsMocks()) { - return await libparsec.mountpointToOsPath(infoResult.value.mountpoints[0][0], entryPath); - } - return { ok: true, value: `/home${entryPath}` }; + return await libparsec.mountpointToOsPath(infoResult.value.mountpoints[0][0], entryPath); } diff --git a/client/src/router/types.ts b/client/src/router/types.ts index 1e0e1afddf7..6e8fdd0d233 100644 --- a/client/src/router/types.ts +++ b/client/src/router/types.ts @@ -55,81 +55,85 @@ const routes: Array<RouteRecordRaw> = [ component: () => import('@/views/client-area/ClientAreaLayout.vue'), }, { - // ConnectedLayout ensure that every children components are provided - // with a fileOperationManager, informationManager and eventDistributor - // that correspond with the current ConnectionHandle. - path: '/connected', - component: () => import('@/views/layouts/ConnectedLayout.vue'), + // DevLayout is used to login a default device in case the page was + // just refreshed and we're using the testbed. + // We have to do it this way because Vue doesn't let us make async calls + // in ConnectedLayout before calling provide(). + path: '/dev', + component: () => import('@/views/layouts/DevLayout.vue'), children: [ { - path: '/sidebar', - component: () => import('@/views/sidebar-menu/SidebarMenuPage.vue'), + // ConnectedLayout ensure that every children components are provided + // with a fileOperationManager, informationManager and eventDistributor + // that correspond with the current ConnectionHandle. + path: '/connected', + component: () => import('@/views/layouts/ConnectedLayout.vue'), children: [ { - path: '/header', - component: () => import('@/views/header/HeaderPage.vue'), + path: '/sidebar', + component: () => import('@/views/sidebar-menu/SidebarMenuPage.vue'), children: [ { - path: '/fileOp', - component: () => import('@/views/layouts/FileOperationLayout.vue'), + path: '/header', + component: () => import('@/views/header/HeaderPage.vue'), children: [ { - path: `/:handle(\\d+)/${Routes.Workspaces}`, - name: Routes.Workspaces, - component: () => import('@/views/workspaces/WorkspacesPage.vue'), + path: '/fileOp', + component: () => import('@/views/layouts/FileOperationLayout.vue'), + children: [ + { + path: `/:handle(\\d+)/${Routes.Workspaces}`, + name: Routes.Workspaces, + component: () => import('@/views/workspaces/WorkspacesPage.vue'), + }, + { + path: `/:handle(\\d+)/${Routes.Documents}`, + name: Routes.Documents, + component: () => import('@/views/files/FoldersPage.vue'), + }, + { + path: `/:handle(\\d+)/${Routes.History}`, + name: Routes.History, + component: () => import('@/views/workspaces/WorkspaceHistoryPage.vue'), + }, + ], }, { - path: `/:handle(\\d+)/${Routes.Documents}`, - name: Routes.Documents, - component: () => import('@/views/files/FoldersPage.vue'), + path: '/:handle(\\d+)', + redirect: { name: Routes.Workspaces }, }, { - path: `/:handle(\\d+)/${Routes.History}`, - name: Routes.History, - component: () => import('@/views/workspaces/WorkspaceHistoryPage.vue'), + path: `/:handle(\\d+)/${Routes.Users}`, + name: Routes.Users, + component: () => import('@/views/users/UsersPage.vue'), + }, + { + path: `/:handle(\\d+)/${Routes.Storage}`, + name: Routes.Storage, + component: () => import('@/views/organizations/StoragePage.vue'), + }, + { + path: `/:handle(\\d+)/${Routes.Organization}`, + name: Routes.Organization, + component: () => import('@/views/organizations/OrganizationInformationPage.vue'), + }, + { + path: `/:handle(\\d+)/${Routes.About}`, + name: Routes.About, + component: () => import('@/views/about/AboutPage.vue'), + }, + { + path: `/:handle(\\d+)/${Routes.MyProfile}`, + name: Routes.MyProfile, + component: () => import('@/views/users/MyProfilePage.vue'), + }, + { + path: `/:handle(\\d+)/${Routes.Viewer}`, + name: Routes.Viewer, + component: () => import('@/views/viewers/FileViewer.vue'), }, ], }, - { - path: '/:handle(\\d+)', - redirect: { name: Routes.Workspaces }, - }, - { - path: '/:handle(\\d+)/:unknown(.+)', - redirect: (to): any => { - return { path: `/${to.params.handle}`, query: {} }; - }, - }, - { - path: `/:handle(\\d+)/${Routes.Users}`, - name: Routes.Users, - component: () => import('@/views/users/UsersPage.vue'), - }, - { - path: `/:handle(\\d+)/${Routes.Storage}`, - name: Routes.Storage, - component: () => import('@/views/organizations/StoragePage.vue'), - }, - { - path: `/:handle(\\d+)/${Routes.Organization}`, - name: Routes.Organization, - component: () => import('@/views/organizations/OrganizationInformationPage.vue'), - }, - { - path: `/:handle(\\d+)/${Routes.About}`, - name: Routes.About, - component: () => import('@/views/about/AboutPage.vue'), - }, - { - path: `/:handle(\\d+)/${Routes.MyProfile}`, - name: Routes.MyProfile, - component: () => import('@/views/users/MyProfilePage.vue'), - }, - { - path: `/:handle(\\d+)/${Routes.Viewer}`, - name: Routes.Viewer, - component: () => import('@/views/viewers/FileViewer.vue'), - }, ], }, ], diff --git a/client/src/services/fileOperationManager.ts b/client/src/services/fileOperationManager.ts index 3b2898b902e..9abacee0683 100644 --- a/client/src/services/fileOperationManager.ts +++ b/client/src/services/fileOperationManager.ts @@ -367,7 +367,7 @@ class FileOperationManager { const srcEntry = statResult.value; if (statResult.value.isFile()) { tree = { - totalSize: (statResult.value as EntryStatFile).size, + totalSize: Number((statResult.value as EntryStatFile).size), entries: [statResult.value as EntryStatFile], maxRecursionReached: false, maxFilesReached: false, @@ -449,7 +449,7 @@ class FileOperationManager { fdW = openWriteResult.value; // Resize the destination - await resizeFile(data.workspaceHandle, fdW, entry.size); + await resizeFile(data.workspaceHandle, fdW, Number(entry.size)); let loop = true; let offset = 0; @@ -593,7 +593,7 @@ class FileOperationManager { } if (statResult.value.isFile()) { tree = { - totalSize: (statResult.value as WorkspaceHistoryEntryStatFile).size, + totalSize: Number((statResult.value as WorkspaceHistoryEntryStatFile).size), entries: [statResult.value as WorkspaceHistoryEntryStatFile], maxRecursionReached: false, maxFilesReached: false, @@ -659,7 +659,7 @@ class FileOperationManager { fdW = openWriteResult.value; // Resize the destination - await resizeFile(data.workspaceHandle, fdW, entry.size); + await resizeFile(data.workspaceHandle, fdW, Number(entry.size)); let loop = true; let offset = 0; @@ -786,7 +786,7 @@ class FileOperationManager { const chunk = value as Uint8Array; await wStream.write(chunk); writtenSize += chunk.byteLength; - await this.sendState(FileOperationState.OperationProgress, data, { progress: (writtenSize / (fileSize || 1)) * 100 }); + await this.sendState(FileOperationState.OperationProgress, data, { progress: (writtenSize / (Number(fileSize) || 1)) * 100 }); } } wStream.close(); diff --git a/client/src/services/hotkeyManager.ts b/client/src/services/hotkeyManager.ts index e5ee20bb4af..f5f69f9070f 100644 --- a/client/src/services/hotkeyManager.ts +++ b/client/src/services/hotkeyManager.ts @@ -1,6 +1,6 @@ // Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS -import { isDesktop, isLinux, isMacOS, isMobile, isWeb, isWindows, needsMocks } from '@/parsec/environment'; +import { isDesktop, isLinux, isMacOS, isMobile, isWeb, isWindows } from '@/parsec/environment'; import { Routes, currentRouteIs } from '@/router'; import { modalController } from '@ionic/vue'; @@ -50,7 +50,7 @@ export class HotkeyGroup { } add(options: HotkeyOptions, callback: () => Promise<void>): void { - if (needsMocks()) { + if (window.isDev() && isWeb()) { options.platforms |= Platforms.Web; } this.hotkeys.push({ diff --git a/client/src/services/informationManager.ts b/client/src/services/informationManager.ts index e7dbee87cbd..8bd9e36fcd1 100644 --- a/client/src/services/informationManager.ts +++ b/client/src/services/informationManager.ts @@ -1,6 +1,6 @@ // Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS -import { ConnectionHandle, EntryName, FsPath, SizeInt, UserID, WorkspaceHandle, WorkspaceRole } from '@/parsec'; +import { ConnectionHandle, EntryName, FsPath, UserID, WorkspaceHandle, WorkspaceRole } from '@/parsec'; import { getConnectionHandle } from '@/router'; import { NotificationManager } from '@/services/notificationManager'; import { modalController } from '@ionic/vue'; @@ -63,7 +63,7 @@ export interface UserSharedDocumentData extends AbstractInformationData { userId: UserID; fileName: EntryName; filePath: FsPath; - fileSize: SizeInt; + fileSize: number; } // All elements the owner's account has been imported is done diff --git a/client/src/services/injectionProvider.ts b/client/src/services/injectionProvider.ts index 53ae86cc4ad..295da3352a1 100644 --- a/client/src/services/injectionProvider.ts +++ b/client/src/services/injectionProvider.ts @@ -1,6 +1,6 @@ // Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS -import { ConnectionHandle, needsMocks } from '@/parsec'; +import { ConnectionHandle, isWeb } from '@/parsec'; import { EventData, EventDistributor, Events } from '@/services/eventDistributor'; import { FileOperationManager } from '@/services/fileOperationManager'; import { Information, InformationManager } from '@/services/informationManager'; @@ -48,7 +48,7 @@ export class InjectionProvider { const inj = this.injections.get(handle); if (!inj) { - if (needsMocks()) { + if (window.isDev() && isWeb()) { return this.getDefault(); } console.warn('Could not get injections for handle', handle); diff --git a/client/src/services/storageManager.ts b/client/src/services/storageManager.ts index 3a48da8e1fa..28653fc0f60 100644 --- a/client/src/services/storageManager.ts +++ b/client/src/services/storageManager.ts @@ -191,6 +191,11 @@ export class StorageManager { async retrieveBmsAccess(): Promise<BmsAccessData | undefined> { return await this.internalStore.get(StorageManager.STORED_BMS_ACCESS_KEY); } + + async clearAll(): Promise<void> { + window.electronAPI.log('warn', 'Clearing all cache'); + await this.internalStore.clear(); + } } class StorageManagerInstance { diff --git a/client/src/views/devices/GreetDeviceModal.vue b/client/src/views/devices/GreetDeviceModal.vue index 01363ba7c76..5efd7ecc161 100644 --- a/client/src/views/devices/GreetDeviceModal.vue +++ b/client/src/views/devices/GreetDeviceModal.vue @@ -149,7 +149,7 @@ <!-- give code step --> <div v-show="pageStep === GreetDeviceStep.ProvideHostSasCode" - class="step" + class="step host-code" > <sas-code-provide :code="greeter.hostSASCode" /> </div> diff --git a/client/src/views/home/DeviceJoinOrganizationModal.vue b/client/src/views/home/DeviceJoinOrganizationModal.vue index 8c7dc4b479c..c6b073840c8 100644 --- a/client/src/views/home/DeviceJoinOrganizationModal.vue +++ b/client/src/views/home/DeviceJoinOrganizationModal.vue @@ -89,7 +89,7 @@ <!-- part 5 (finish the process)--> <div v-show="pageStep === DeviceJoinOrganizationStep.Finish" - class="step" + class="step final-step" > <ms-informative-text :icon="checkmarkCircle"> {{ $msTranslate('ClaimDeviceModal.subtitles.done') }} diff --git a/client/src/views/layouts/ConnectedLayout.vue b/client/src/views/layouts/ConnectedLayout.vue index 95e2e6d28e0..10eaefd3756 100644 --- a/client/src/views/layouts/ConnectedLayout.vue +++ b/client/src/views/layouts/ConnectedLayout.vue @@ -8,18 +8,9 @@ </template> <script lang="ts" setup> -import { - getConnectionInfo, - getTOS, - needsMocks, - logout as parsecLogout, - acceptTOS, - mockLoggedInDevice, - WorkspaceRole, - getClientInfo, -} from '@/parsec'; +import { getConnectionInfo, getTOS, logout as parsecLogout, acceptTOS, getClientInfo } from '@/parsec'; import { getConnectionHandle, navigateTo, Routes } from '@/router'; -import { EventData, EventDistributor, EventDistributorKey, Events } from '@/services/eventDistributor'; +import { EventData, EventDistributorKey, Events } from '@/services/eventDistributor'; import { FileOperationManagerKey } from '@/services/fileOperationManager'; import { Information, InformationLevel, InformationManagerKey, PresentationMode } from '@/services/informationManager'; import { InjectionProvider, InjectionProviderKey, Injections } from '@/services/injectionProvider'; @@ -31,7 +22,6 @@ import { MsModalResult, openSpinnerModal } from 'megashark-lib'; import { DateTime } from 'luxon'; import { StorageManagerKey, StorageManager } from '@/services/storageManager'; import { recentDocumentManager } from '@/services/recentDocuments'; -import { FileContentType } from '@/common/fileTypes'; const injectionProvider: InjectionProvider = inject(InjectionProviderKey)!; const storageManager: StorageManager = inject(StorageManagerKey)!; @@ -52,14 +42,7 @@ onMounted(async () => { return; } - // When in dev mode, we often open directly a connected page, - // so a few states are not properly set. - if (needsMocks()) { - if (!injectionProvider.hasInjections(handle)) { - injectionProvider.createNewInjections(handle, new EventDistributor()); - } - mockLoggedInDevice(); - } + // Vue wants `provide` to be the absolute first thing. injections = injectionProvider.getInjections(handle); // Provide the injections to children @@ -88,7 +71,7 @@ onMounted(async () => { recentDocumentManager.resetHistory(); await recentDocumentManager.loadFromStorage(storageManager, handle); - await mockRecentDocuments(); + // await mockRecentDocuments(); initialized.value = true; @@ -132,48 +115,6 @@ async function tryOpeningTOSModal(): Promise<void> { } } -async function mockRecentDocuments(): Promise<void> { - // Adds fake files and workspace by default in dev mode - // to make sure we keep the feature in mind - if (needsMocks()) { - recentDocumentManager.addFile({ - entryId: crypto.randomUUID().toString(), - workspaceHandle: 1337, - path: '/a/b/File_Fake image.png', - name: 'File_Fake image.png', - contentType: { - type: FileContentType.Image, - extension: 'png', - mimeType: 'image/png', - }, - }); - recentDocumentManager.addFile({ - entryId: crypto.randomUUID().toString(), - workspaceHandle: 1337, - path: '/a/b/File_Fake PDF document.pdf', - name: 'File_Fake PDF document.pdf', - contentType: { - type: FileContentType.PdfDocument, - extension: 'pdf', - mimeType: 'application/pdf', - }, - }); - recentDocumentManager.addWorkspace({ - id: '1', - currentName: 'Trademeet', - currentSelfRole: WorkspaceRole.Owner, - size: 934_583, - lastUpdated: DateTime.now().minus(2000), - availableOffline: false, - isStarted: false, - isBootstrapped: false, - sharing: [], - mountpoints: [[1, '/home/a']], - handle: 1, - }); - } -} - async function logout(): Promise<void> { const modal = await openSpinnerModal('HomePage.topbar.logoutWait'); const menuCtrls = useUploadMenu(); diff --git a/client/src/views/layouts/DevLayout.vue b/client/src/views/layouts/DevLayout.vue new file mode 100644 index 00000000000..fbf0dd821c0 --- /dev/null +++ b/client/src/views/layouts/DevLayout.vue @@ -0,0 +1,124 @@ +<!-- Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS --> + +<template> + <ion-page v-if="initialized"> + <ion-router-outlet /> + </ion-page> +</template> + +<script setup lang="ts"> +import { inject, onMounted, ref } from 'vue'; +import { IonPage, IonRouterOutlet } from '@ionic/vue'; +import { InjectionProvider, InjectionProviderKey } from '@/services/injectionProvider'; +import { EventDistributor } from '@/services/eventDistributor'; +import { + AccessStrategy, + closeFile, + createWorkspace, + getLoggedInDevices, + listAvailableDevices, + login, + openFile, + startWorkspace, + writeFile, +} from '@/parsec'; +import { getConnectionHandle, navigateTo, Routes } from '@/router'; +import { StorageManagerKey, StorageManager } from '@/services/storageManager'; + +const injectionProvider: InjectionProvider = inject(InjectionProviderKey)!; +const storageManager: StorageManager = inject(StorageManagerKey)!; +const initialized = ref(false); +const DEV_DEFAULT_HANDLE = 1; + +onMounted(async () => { + initialized.value = false; + const handle = getConnectionHandle(); + + if (!handle) { + window.electronAPI.log('error', 'Failed to retrieve connection handle while logged in'); + await navigateTo(Routes.Home, { replace: true, skipHandle: true }); + return; + } + + if (!import.meta.env.PARSEC_APP_TESTBED_SERVER || (await getLoggedInDevices()).length !== 0) { + initialized.value = true; + return; + } + + // When in dev mode, we often open directly a connected page, + // so a few states are not properly set. + if (handle !== DEV_DEFAULT_HANDLE) { + window.electronAPI.log('error', `In dev mode, you should use "${DEV_DEFAULT_HANDLE}" as the default handle`); + // eslint-disable-next-line no-alert + alert(`Use "${DEV_DEFAULT_HANDLE}" as the default handle when not connecting properly`); + return; + } + window.electronAPI.log('info', 'Page was refreshed, login in a default device'); + injectionProvider.createNewInjections(DEV_DEFAULT_HANDLE, new EventDistributor()); + const devices = await listAvailableDevices(); + let device = devices.find((d) => d.humanHandle.label === 'Alicey McAliceFace'); + + if (!device) { + device = devices[0]; + window.electronAPI.log('error', `Could not find Alice device, using ${device.humanHandle.label}`); + } + + const result = await login( + injectionProvider.getInjections(DEV_DEFAULT_HANDLE).eventDistributor, + device, + AccessStrategy.usePassword(device, 'P@ssw0rd.'), + ); + if (!result.ok) { + window.electronAPI.log('error', `Failed to log in on a default device: ${JSON.stringify(result.error)}`); + } else if (result.value !== DEV_DEFAULT_HANDLE) { + window.electronAPI.log('error', `Lib returned handle ${result.value} instead of ${DEV_DEFAULT_HANDLE}`); + } else { + window.electronAPI.log('info', `Logged in as ${device.humanHandle.label}`); + } + + if (import.meta.env.PARSEC_APP_CLEAR_CACHE === 'true') { + await storageManager.clearAll(); + } + if (import.meta.env.PARSEC_APP_CREATE_DEFAULT_WORKSPACES === 'true') { + await populate(); + } + + initialized.value = true; +}); + +async function populate(): Promise<void> { + // Avoid importing files if unnecessary + const mockFiles = (await import('@/parsec/mock_files')); + + window.electronAPI.log('debug', 'Creating mock workspaces and files'); + for (const workspaceName of ['The Copper Coronet', 'Trademeet', "Watcher's Keep"]) { + const wkResult = await createWorkspace(workspaceName); + if (!wkResult.ok) { + window.electronAPI.log('error', `Could not create dev workspace ${workspaceName}`); + continue; + } + const startWkResult = await startWorkspace(wkResult.value); + if (!startWkResult.ok) { + window.electronAPI.log('error', `Could not start dev workspace ${workspaceName}`); + continue; + } + for (const fileType in mockFiles.MockFileType) { + console.log(workspaceName, fileType); + const fileName = `document_${fileType}.${fileType.toLocaleLowerCase()}`; + const openResult = await openFile(startWkResult.value, `/${fileName}`, { write: true, truncate: true, create: true }); + + if (!openResult.ok) { + window.electronAPI.log('error', `Could not open file ${fileName}`); + continue; + } + const content = await mockFiles.getMockFileContent(fileType as any); + const writeResult = await writeFile(startWkResult.value, openResult.value, 0, content); + if (!writeResult.ok) { + window.electronAPI.log('error', `Failed to write file ${fileName}`); + continue; + } + await closeFile(startWkResult.value, openResult.value); + } + } +} +</script> diff --git a/client/src/views/layouts/LoadingLayout.vue b/client/src/views/layouts/LoadingLayout.vue index 4a019a61631..5f5f6e5ad24 100644 --- a/client/src/views/layouts/LoadingLayout.vue +++ b/client/src/views/layouts/LoadingLayout.vue @@ -18,7 +18,6 @@ <script setup lang="ts"> import { Base64, LogoIconGradient, MsImage, MsSpinner } from 'megashark-lib'; -import { needsMocks } from '@/parsec'; import { RouteBackup, Routes, getCurrentRouteQuery, navigateTo } from '@/router'; import { IonContent, IonPage } from '@ionic/vue'; import { onMounted } from 'vue'; @@ -32,7 +31,8 @@ onMounted(async () => { // in every component. // To force a reload, we first navigate to a loading page (/loading), // then to the connected organization. - // We masquerade this as a feature, showing the user a "please wait" message. + // If we do it too fast, it causes a blink, so we masquerade this as a feature, + // showing the user a "please wait" message. setTimeout( async () => { const query = getCurrentRouteQuery(); @@ -54,7 +54,7 @@ onMounted(async () => { await navigateTo(Routes.Home, { skipHandle: true, replace: true }); } }, - needsMocks() ? 0 : 1500, + import.meta.env.PARSEC_APP_TESTBED_SERVER ? 0 : 1500, ); }); </script> diff --git a/client/src/views/organizations/creation/CreateOrganizationSaas.vue b/client/src/views/organizations/creation/CreateOrganizationSaas.vue index 36ccc2456c0..d34c19fad1b 100644 --- a/client/src/views/organizations/creation/CreateOrganizationSaas.vue +++ b/client/src/views/organizations/creation/CreateOrganizationSaas.vue @@ -212,6 +212,7 @@ async function onCreateClicked(): Promise<void> { if (!props.bootstrapLink) { const response = await BmsAccessInstance.get().createOrganization(organizationName.value); + console.log(response); if (response.isError) { console.log('Failed to create organization'); // TODO: Change this error handling with the real backend response diff --git a/client/src/views/users/GreetUserModal.vue b/client/src/views/users/GreetUserModal.vue index fda5af6469e..1bfa5381ae6 100644 --- a/client/src/views/users/GreetUserModal.vue +++ b/client/src/views/users/GreetUserModal.vue @@ -50,7 +50,7 @@ <!-- give code step --> <div v-show="pageStep === GreetUserStep.ProvideHostSasCode" - class="step" + class="step host-code" > <sas-code-provide :code="greeter.hostSASCode" /> </div> @@ -96,7 +96,7 @@ :title="'UsersPage.greet.profileDropdownTitle'" :label="'UsersPage.greet.profileDropdownPlaceholder'" :options="profileOptions" - @change="setUserProfile($event.option.key as UserProfile)" + @change="setUserProfile" /> </div> @@ -178,9 +178,10 @@ import { MsSpinner, MsWizardStepper, Translatable, + MsDropdownChangeEvent, } from 'megashark-lib'; import { close } from 'ionicons/icons'; -import { Ref, computed, onMounted, onUnmounted, ref, watch } from 'vue'; +import { Ref, computed, onMounted, ref } from 'vue'; enum GreetUserStep { WaitForGuest = 1, @@ -240,13 +241,10 @@ function getTitleAndSubtitle(): [Translatable, Translatable] { return ['', '']; } -function setUserProfile(role: UserProfile): void { - profile.value = role; -} - -const unwatchProfile = watch(profile, async () => { +async function setUserProfile(event: MsDropdownChangeEvent): Promise<void> { + profile.value = event.option.key; await updateCanGoForward(); -}); +} async function updateCanGoForward(): Promise<void> { if (pageStep.value === GreetUserStep.WaitForGuest && waitingForGuest.value === true) { @@ -492,10 +490,6 @@ async function nextStep(): Promise<void> { onMounted(async () => { await startProcess(); }); - -onUnmounted(async () => { - unwatchProfile(); -}); </script> <style scoped lang="scss"> diff --git a/client/src/views/users/UsersPage.vue b/client/src/views/users/UsersPage.vue index a36f548254c..65ed5e1e288 100644 --- a/client/src/views/users/UsersPage.vue +++ b/client/src/views/users/UsersPage.vue @@ -160,7 +160,7 @@ import { ClientUserUpdateProfileError, ClientUserUpdateProfileErrorTag, } from '@/parsec'; -import { Routes, getCurrentRouteQuery, watchRoute, currentRouteIsUserRoute } from '@/router'; +import { Routes, getCurrentRouteQuery, watchRoute, currentRouteIsUserRoute, navigateTo } from '@/router'; import { HotkeyGroup, HotkeyManager, HotkeyManagerKey, Modifiers, Platforms } from '@/services/hotkeyManager'; import { Information, InformationLevel, InformationManager, InformationManagerKey, PresentationMode } from '@/services/informationManager'; import { StorageManager, StorageManagerKey } from '@/services/storageManager'; @@ -614,6 +614,7 @@ const routeWatchCancel = watchRoute(async () => { const query = getCurrentRouteQuery(); if (query.openInvite) { await inviteUser(); + await navigateTo(Routes.Users, { replace: true, query: {} }); } await refreshUserList(); }); @@ -649,6 +650,7 @@ onMounted(async (): Promise<void> => { const query = getCurrentRouteQuery(); if (query.openInvite) { await inviteUser(); + await navigateTo(Routes.Users, { replace: true, query: {} }); } }); diff --git a/client/src/views/viewers/FileViewer.vue b/client/src/views/viewers/FileViewer.vue index 8fe8173a3a9..68a5fc9de25 100644 --- a/client/src/views/viewers/FileViewer.vue +++ b/client/src/views/viewers/FileViewer.vue @@ -170,7 +170,7 @@ async function _getFileInfoAt( return; } const info: FileContentInfo = { - data: new Uint8Array((statsResult.value as WorkspaceHistoryEntryStatFile).size), + data: new Uint8Array(Number((statsResult.value as WorkspaceHistoryEntryStatFile).size)), extension: fileInfo.extension, mimeType: fileInfo.mimeType, fileName: fileName, @@ -221,7 +221,7 @@ async function _getFileInfo( return; } const info: FileContentInfo = { - data: new Uint8Array((statsResult.value as EntryStatFile).size), + data: new Uint8Array(Number((statsResult.value as EntryStatFile).size)), extension: fileInfo.extension, mimeType: fileInfo.mimeType, fileName: fileName, diff --git a/client/src/views/viewers/PdfViewer.vue b/client/src/views/viewers/PdfViewer.vue index 3334b0c89d1..74119996095 100644 --- a/client/src/views/viewers/PdfViewer.vue +++ b/client/src/views/viewers/PdfViewer.vue @@ -57,7 +57,7 @@ import { FileControls, FileControlsButton, FileControlsPagination, FileControlsZ import { MsSpinner, MsReportText, MsReportTheme, I18n } from 'megashark-lib'; import * as pdfjs from 'pdfjs-dist'; import { scan } from 'ionicons/icons'; -import { needsMocks } from '@/parsec'; +import { isWeb } from '@/parsec'; const props = defineProps<{ contentInfo: FileContentInfo; @@ -118,7 +118,7 @@ async function loadPage(pageIndex: number): Promise<void> { try { const page = await pdf.value.getPage(pageIndex); - if (needsMocks() && pageIndex === 4) { + if (window.isDev() && isWeb() && pageIndex === 4) { throw new Error('Failed to load page'); } diff --git a/client/src/views/workspaces/WorkspacesPage.vue b/client/src/views/workspaces/WorkspacesPage.vue index 28644998191..f766e1911c8 100644 --- a/client/src/views/workspaces/WorkspacesPage.vue +++ b/client/src/views/workspaces/WorkspacesPage.vue @@ -43,7 +43,7 @@ <div class="workspaces-container scroll"> <div v-show="querying && filteredWorkspaces.length === 0" - class="no-workspaces-content" + class="no-workspaces-loading" > <ms-spinner :title="'WorkspacesPage.loading'" /> </div> @@ -187,6 +187,7 @@ import { decryptFileLink, entryStat, getClientProfile, + isDesktop, parseFileLink, createWorkspace as parsecCreateWorkspace, getWorkspaceSharing as parsecGetWorkspaceSharing, @@ -414,7 +415,7 @@ async function refreshWorkspacesList(): Promise<void> { } else { console.warn(`Failed to get sharing for ${wk.currentName}`); } - if (wk.mountpoints.length === 0) { + if (isDesktop() && wk.mountpoints.length === 0) { const mountResult = await parsecMountWorkspace(wk.handle); if (mountResult.ok) { wk.mountpoints.push(mountResult.value); @@ -549,7 +550,8 @@ async function onOpenWorkspaceContextMenu(workspace: WorkspaceInfo, event: Event height: 100%; align-items: center; - &-content { + &-content, + &-loading { border-radius: var(--parsec-radius-8); display: flex; height: fit-content; diff --git a/client/tests/component/specs/testFileCard.spec.ts b/client/tests/component/specs/testFileCard.spec.ts index fbeac6a344b..b672aee2153 100644 --- a/client/tests/component/specs/testFileCard.spec.ts +++ b/client/tests/component/specs/testFileCard.spec.ts @@ -30,7 +30,7 @@ describe('File Card Item', () => { baseVersion: 1, isPlaceholder: false, needSync: false, - size: 43_297_832_478, + size: BigInt(43_297_832_478), name: 'A File.txt', path: '/', isFile: (): boolean => true, diff --git a/client/tests/component/specs/testFileListItem.spec.ts b/client/tests/component/specs/testFileListItem.spec.ts index 3503065f18f..71eebe39d00 100644 --- a/client/tests/component/specs/testFileListItem.spec.ts +++ b/client/tests/component/specs/testFileListItem.spec.ts @@ -33,7 +33,7 @@ describe('File List Item', () => { baseVersion: 1, isPlaceholder: false, needSync: false, - size: 43_297_832_478, + size: BigInt(43_297_832_478), name: 'A File.txt', path: '/', isFile: (): boolean => true, diff --git a/client/tests/e2e/data/imports/audio.mp3 b/client/tests/e2e/data/imports/audio.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..fa7474c3dca5271be56d875aaebb647584b95afa GIT binary patch literal 41866 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 literal 0 HcmV?d00001 diff --git a/client/tests/e2e/data/imports/code.py b/client/tests/e2e/data/imports/code.py new file mode 100644 index 00000000000..56f479500c5 --- /dev/null +++ b/client/tests/e2e/data/imports/code.py @@ -0,0 +1,31 @@ +# Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS + +import argparse +import sys +import pathlib + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument( + "-i", "--input", type=pathlib.Path, required=True, help="File to convert to Uint8Array" + ) + parser.add_argument("--name", type=str, required=True, help="Name of the variable") + parser.add_argument("-o", "--output", default=sys.stdout, help="Where to put the result") + args = parser.parse_args() + content = args.input.read_bytes() + array = ",".join([str(c) for c in content]) + result = f""" +// Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS + +/* +Generated automatically with {sys.argv[0]} +*/ + +export const {args.name} = new Uint8Array([{array}]); +""" + + if args.output is sys.stdout: + print(result) + else: + with open(args.output, "w+") as fd: + fd.write(result) diff --git a/client/tests/e2e/data/imports/document.docx b/client/tests/e2e/data/imports/document.docx new file mode 100644 index 0000000000000000000000000000000000000000..07ceaea2078de3cb5ddf98d4481a2530f3dbab0e GIT binary patch literal 15580 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 literal 0 HcmV?d00001 diff --git a/client/tests/e2e/data/imports/image.png b/client/tests/e2e/data/imports/image.png new file mode 100644 index 0000000000000000000000000000000000000000..0062f4d81d5b69841dc4d1ba8ff3c4c62b237a75 GIT binary patch literal 6335 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 COY@fi literal 0 HcmV?d00001 diff --git a/client/tests/e2e/data/imports/pdfDocument.pdf b/client/tests/e2e/data/imports/pdfDocument.pdf new file mode 100644 index 0000000000000000000000000000000000000000..89e3cf12e1131d5b3e53c254497c95cea84f4e52 GIT binary patch literal 78731 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�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 literal 0 HcmV?d00001 diff --git a/client/tests/e2e/data/imports/spreadsheet.xlsx b/client/tests/e2e/data/imports/spreadsheet.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..8e351794c47e4a15ec330994e05e801bc011c635 GIT binary patch literal 6139 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 literal 0 HcmV?d00001 diff --git a/client/tests/e2e/data/imports/text.txt b/client/tests/e2e/data/imports/text.txt new file mode 100644 index 00000000000..59115050716 --- /dev/null +++ b/client/tests/e2e/data/imports/text.txt @@ -0,0 +1 @@ +A simple text file diff --git a/client/tests/e2e/data/imports/video.mp4 b/client/tests/e2e/data/imports/video.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..f938acf784e2cfa33ba8090c1ae58c043ddaccac GIT binary patch literal 176994 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%0D9P?fq4KB*w_OjqdD(i3aj_jD#jj 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ዜQ=a`bwT2FIe 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 literal 0 HcmV?d00001 diff --git a/client/tests/e2e/helpers/assertions.ts b/client/tests/e2e/helpers/assertions.ts index 8b07cdc32c5..a4e141a20c6 100644 --- a/client/tests/e2e/helpers/assertions.ts +++ b/client/tests/e2e/helpers/assertions.ts @@ -1,6 +1,7 @@ // Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS import { expect as baseExpect, Locator, Page } from '@playwright/test'; +import { dismissToast } from '@tests/e2e/helpers/utils'; interface AssertReturnType { message: () => string; @@ -69,8 +70,7 @@ export const expect = baseExpect.extend({ } } - // Close toast - await toast.locator('.toast-button-confirm').click(); + await dismissToast(page); await expect(toast).toBeHidden(); return { diff --git a/client/tests/e2e/helpers/bms.ts b/client/tests/e2e/helpers/bms.ts index 5737e04dd34..4ca26e8b85d 100644 --- a/client/tests/e2e/helpers/bms.ts +++ b/client/tests/e2e/helpers/bms.ts @@ -3,12 +3,8 @@ /* eslint-disable camelcase */ import { Page, Route } from '@playwright/test'; -import { - DEFAULT_ORGANIZATION_DATA_SLICE, - DEFAULT_ORGANIZATION_INFORMATION, - DEFAULT_USER_INFORMATION, - UserData, -} from '@tests/e2e/helpers/data'; +import { DEFAULT_ORGANIZATION_DATA_SLICE, DEFAULT_USER_INFORMATION } from '@tests/e2e/helpers/data'; +import { MsPage } from '@tests/e2e/helpers/fixtures'; import { DateTime } from 'luxon'; async function mockRoute( @@ -188,18 +184,18 @@ interface MockUserOverload { noClient?: boolean; } -async function mockUserRoute(page: Page, overload: MockUserOverload = {}, options?: MockRouteOptions): Promise<void> { +async function mockUserRoute(page: MsPage, overload: MockUserOverload = {}, options?: MockRouteOptions): Promise<void> { await mockRoute(page, `**/users/${DEFAULT_USER_INFORMATION.id}`, options, async (route) => { if (route.request().method() === 'GET') { let client = null; if (!overload.noClient) { client = { - firstname: UserData.firstName, - lastname: UserData.lastName, + firstname: page.userData.firstName, + lastname: page.userData.lastName, id: '1337', - job: UserData.job, - company: UserData.company, - phone: UserData.phone, + job: page.userData.job, + company: page.userData.company, + phone: page.userData.phone, billing_system: overload.billingSystem ?? 'STRIPE', }; } @@ -209,7 +205,7 @@ async function mockUserRoute(page: Page, overload: MockUserOverload = {}, option json: { id: DEFAULT_USER_INFORMATION.id, created_at: '2024-07-15T13:21:32.141317Z', - email: UserData.email, + email: page.userData.email, client: client, }, }); @@ -217,19 +213,19 @@ async function mockUserRoute(page: Page, overload: MockUserOverload = {}, option const data = await route.request().postDataJSON(); if (data.client) { if (data.client.firstname) { - UserData.firstName = data.client.firstname; + page.userData.firstName = data.client.firstname; } if (data.client.lastname) { - UserData.lastName = data.client.lastname; + page.userData.lastName = data.client.lastname; } if (data.client.phone) { - UserData.phone = data.client.phone; + page.userData.phone = data.client.phone; } if (data.client.job || data.client.job === null) { - UserData.job = data.client.job; + page.userData.job = data.client.job; } if (data.client.company || data.client.job === null) { - UserData.company = data.client.company; + page.userData.company = data.client.company; } } await route.fulfill({ @@ -255,7 +251,7 @@ async function mockCreateOrganization(page: Page, bootstrapAddr: string, options ); } -async function mockListOrganizations(page: Page, options?: MockRouteOptions): Promise<void> { +async function mockListOrganizations(page: MsPage, options?: MockRouteOptions): Promise<void> { await mockRoute( page, `**/users/${DEFAULT_USER_INFORMATION.id}/clients/${DEFAULT_USER_INFORMATION.clientId}/organizations`, @@ -266,22 +262,22 @@ async function mockListOrganizations(page: Page, options?: MockRouteOptions): Pr json: { results: [ { - pk: DEFAULT_ORGANIZATION_INFORMATION.bmsId, + pk: page.orgInfo.bmsId, created_at: '2024-12-04T00:00:00.000', expiration_date: null, - name: DEFAULT_ORGANIZATION_INFORMATION.name, - parsec_id: DEFAULT_ORGANIZATION_INFORMATION.name, - suffix: DEFAULT_ORGANIZATION_INFORMATION.name, + name: page.orgInfo.name, + parsec_id: page.orgInfo.name, + suffix: page.orgInfo.name, stripe_subscription_id: 'stripe_id', bootstrap_link: '', }, { - pk: `${DEFAULT_ORGANIZATION_INFORMATION.bmsId}-2`, + pk: `${page.orgInfo.bmsId}-2`, created_at: '2024-12-04T00:00:00.000', expiration_date: null, - name: DEFAULT_ORGANIZATION_INFORMATION.name, - parsec_id: `${DEFAULT_ORGANIZATION_INFORMATION.name}-2`, - suffix: `${DEFAULT_ORGANIZATION_INFORMATION.name}-2`, + name: page.orgInfo.name, + parsec_id: `${page.orgInfo.name}-2`, + suffix: `${page.orgInfo.name}-2`, stripe_subscription_id: 'stripe_id2', bootstrap_link: '', }, @@ -379,7 +375,7 @@ interface MockGetInvoicesOverload { count?: number; } -async function mockGetInvoices(page: Page, overload: MockGetInvoicesOverload = {}, options?: MockRouteOptions): Promise<void> { +async function mockGetInvoices(page: MsPage, overload: MockGetInvoicesOverload = {}, options?: MockRouteOptions): Promise<void> { await mockRoute( page, `**/users/${DEFAULT_USER_INFORMATION.id}/clients/${DEFAULT_USER_INFORMATION.clientId}/invoices`, @@ -395,7 +391,7 @@ async function mockGetInvoices(page: Page, overload: MockGetInvoicesOverload = { period_end: DateTime.fromObject({ year: year, month: month }).endOf('month').toFormat('yyyy-LL-dd'), total: Math.round(Math.random() * 1000000), status: ['paid', 'draft', 'open'][Math.floor(Math.random() * 3)], - organization: DEFAULT_ORGANIZATION_INFORMATION.name, + organization: page.orgInfo.name, number: `${year}-${month}`, receiptNumber: `${year}-${month}`, }); @@ -430,7 +426,7 @@ interface MockBillingDetailsOverload { }; } -async function mockBillingDetails(page: Page, overload: MockBillingDetailsOverload = {}, options?: MockRouteOptions): Promise<void> { +async function mockBillingDetails(page: MsPage, overload: MockBillingDetailsOverload = {}, options?: MockRouteOptions): Promise<void> { await mockRoute( page, `**/users/${DEFAULT_USER_INFORMATION.id}/clients/${DEFAULT_USER_INFORMATION.clientId}/billing_details`, @@ -460,14 +456,14 @@ async function mockBillingDetails(page: Page, overload: MockBillingDetailsOverlo await route.fulfill({ status: 200, json: { - email: overload.email ?? UserData.email, - name: overload.name ?? `${UserData.firstName} ${UserData.lastName}`, + email: overload.email ?? page.userData.email, + name: overload.name ?? `${page.userData.firstName} ${page.userData.lastName}`, address: { - line1: (overload.address && overload.address.line1) ?? UserData.address.line1, + line1: (overload.address && overload.address.line1) ?? page.userData.address.line1, line2: (overload.address && overload.address.line2) ?? '', - city: (overload.address && overload.address.city) ?? UserData.address.city, - postal_code: (overload.address && overload.address.postalCode) ?? UserData.address.postalCode, - country: (overload.address && overload.address.country) ?? UserData.address.country, + city: (overload.address && overload.address.city) ?? page.userData.address.city, + postal_code: (overload.address && overload.address.postalCode) ?? page.userData.address.postalCode, + country: (overload.address && overload.address.country) ?? page.userData.address.country, }, payment_methods: paymentMethods, }, @@ -476,19 +472,19 @@ async function mockBillingDetails(page: Page, overload: MockBillingDetailsOverlo const data = await route.request().postDataJSON(); if (data.address) { if (data.address.line1) { - UserData.address.line1 = data.address.line1; + page.userData.address.line1 = data.address.line1; } if (data.address.line2) { - UserData.address.line2 = data.address.line2; + page.userData.address.line2 = data.address.line2; } if (data.address.postal_code) { - UserData.address.postalCode = data.address.postal_code; + page.userData.address.postalCode = data.address.postal_code; } if (data.address.city) { - UserData.address.line1 = data.address.city; + page.userData.address.line1 = data.address.city; } if (data.address.country) { - UserData.address.line1 = data.address.country; + page.userData.address.line1 = data.address.country; } } await route.fulfill({ @@ -555,11 +551,11 @@ async function mockUpdateEmailSendCode(page: Page, options?: MockRouteOptions): }); } -async function mockUpdateEmail(page: Page, options?: MockRouteOptions): Promise<void> { +async function mockUpdateEmail(page: MsPage, options?: MockRouteOptions): Promise<void> { await mockRoute(page, `**/users/${DEFAULT_USER_INFORMATION.id}/update_email`, options, async (route) => { const data = await route.request().postDataJSON(); if (data.email) { - UserData.email = data.email; + page.userData.email = data.email; } await route.fulfill({ status: 200, @@ -584,7 +580,7 @@ async function mockChangePassword(page: Page, options?: MockRouteOptions): Promi } async function mockCustomOrderDetails( - page: Page, + page: MsPage, overload: MockCustomOrderDetailsOverload = {}, options?: MockRouteOptions, ): Promise<void> { @@ -597,7 +593,7 @@ async function mockCustomOrderDetails( await route.fulfill({ status: 200, json: { - [DEFAULT_ORGANIZATION_INFORMATION.name]: createCustomOrderInvoices(1, overload)[0], + [page.orgInfo.name]: createCustomOrderInvoices(1, overload)[0], }, }); }, @@ -608,9 +604,9 @@ interface MockCustomOrderStatusOverload { status: 'invoice_paid' | 'nothing_linked' | 'unknown' | 'contract_ended' | 'invoice_to_be_paid' | 'estimate_linked'; } -async function mockCustomOrderStatus(page: Page, overload?: MockCustomOrderStatusOverload, options?: MockRouteOptions): Promise<void> { +async function mockCustomOrderStatus(page: MsPage, overload?: MockCustomOrderStatusOverload, options?: MockRouteOptions): Promise<void> { const data: { [key: string]: string } = {}; - data[DEFAULT_ORGANIZATION_INFORMATION.name] = overload ? overload.status : 'invoice_paid'; + data[page.orgInfo.name] = overload ? overload.status : 'invoice_paid'; await mockRoute( page, @@ -625,7 +621,7 @@ async function mockCustomOrderStatus(page: Page, overload?: MockCustomOrderStatu ); } -async function mockCreateCustomOrderRequest(page: Page, options?: MockRouteOptions): Promise<void> { +async function mockCreateCustomOrderRequest(page: MsPage, options?: MockRouteOptions): Promise<void> { await mockRoute(page, '**/custom_order_requests', options, async (route) => { await route.fulfill({ status: 204, @@ -633,7 +629,7 @@ async function mockCreateCustomOrderRequest(page: Page, options?: MockRouteOptio }); } -async function mockGetCustomOrderRequests(page: Page, options?: MockRouteOptions): Promise<void> { +async function mockGetCustomOrderRequests(page: MsPage, options?: MockRouteOptions): Promise<void> { await mockRoute(page, '**/custom_order_requests', options, async (route) => { await route.fulfill({ status: 200, @@ -665,7 +661,7 @@ async function mockGetCustomOrderRequests(page: Page, options?: MockRouteOptions } async function mockGetCustomOrderInvoices( - page: Page, + page: MsPage, options?: MockRouteOptions, overload: MockCustomOrderDetailsOverload = {}, ): Promise<void> { @@ -677,7 +673,7 @@ async function mockGetCustomOrderInvoices( await route.fulfill({ status: 200, json: { - [DEFAULT_ORGANIZATION_INFORMATION.name]: createCustomOrderInvoices(12, overload), + [page.orgInfo.name]: createCustomOrderInvoices(12, overload), }, }); }, diff --git a/client/tests/e2e/helpers/data.ts b/client/tests/e2e/helpers/data.ts index 3cada8c3870..caff4858447 100644 --- a/client/tests/e2e/helpers/data.ts +++ b/client/tests/e2e/helpers/data.ts @@ -1,5 +1,29 @@ // Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS +import { getOrganizationAddr, getServerAddr } from '@tests/e2e/helpers/utils'; +import { randomInt } from 'crypto'; + +export interface UserInformation { + id: string; + clientId: string; + name: string; + firstName: string; + lastName: string; + email: string; + password: string; + job: string; + company: string; + phone?: string; + address: { + line1: string; + postalCode: string; + city: string; + state: string; + country: string; + full: string; + }; +} + export const DEFAULT_USER_INFORMATION = { id: '4242', clientId: '1337', @@ -21,21 +45,29 @@ export const DEFAULT_USER_INFORMATION = { }, }; -export const DEFAULT_ORGANIZATION_INFORMATION = { - name: 'BlackMesa', - // cspell:disable-next-line - addr: 'parsec3://blackmesa.com/BlackMesa', - // cspell:disable-next-line - serverAddr: 'parsec3://blackmesa.com', - bmsId: '42', -}; +export interface OrganizationInformation { + name: string; + addr: string; + serverAddr: string; + bmsId: string; +} + +export function generateDefaultOrganizationInformation(): OrganizationInformation { + const name = `BlackMesa${randomInt(2 ** 47)}`; + return { + name: name, + addr: getOrganizationAddr(name), + serverAddr: getServerAddr(), + bmsId: '42', + }; +} export const DEFAULT_ORGANIZATION_DATA_SLICE = { free: 1024 * 1024 * 1024 * 200, // 200 Gb paying: 1024 * 1024 * 1024 * 100, // 100 Gb }; -class _UserData { +export class UserData { firstName: string; lastName: string; email: string; @@ -81,4 +113,6 @@ class _UserData { } } -export const UserData = new _UserData(); +export function generateDefaultUserData(): UserData { + return new UserData(); +} diff --git a/client/tests/e2e/helpers/fixtures.ts b/client/tests/e2e/helpers/fixtures.ts index fe5fb9fa369..22cc814d5ff 100644 --- a/client/tests/e2e/helpers/fixtures.ts +++ b/client/tests/e2e/helpers/fixtures.ts @@ -1,29 +1,52 @@ // Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS -import { Locator, Page, test as base } from '@playwright/test'; +import { BrowserContext, Locator, Page, TestInfo, test as base } from '@playwright/test'; import { expect } from '@tests/e2e/helpers/assertions'; import { MockBms } from '@tests/e2e/helpers/bms'; -import { DEFAULT_ORGANIZATION_INFORMATION, DEFAULT_USER_INFORMATION, UserData } from '@tests/e2e/helpers/data'; +import { + DEFAULT_USER_INFORMATION, + OrganizationInformation, + UserData, + generateDefaultOrganizationInformation, + generateDefaultUserData, +} from '@tests/e2e/helpers/data'; import { dropTestbed, newTestbed } from '@tests/e2e/helpers/testbed'; -import { fillInputModal, fillIonInput } from '@tests/e2e/helpers/utils'; +import { createWorkspace, dismissToast, dragAndDropFile, fillInputModal, fillIonInput } from '@tests/e2e/helpers/utils'; +import path from 'path'; + +export interface MsPage extends Page { + userData: UserData; + orgInfo: OrganizationInformation; +} export const msTest = base.extend<{ - home: Page; - connected: Page; - documents: Page; - documentsReadOnly: Page; - usersPage: Page; - organizationPage: Page; - myProfilePage: Page; + context: BrowserContext; + home: MsPage; + secondTab: MsPage; + connected: MsPage; + workspaces: MsPage; + documents: MsPage; + documentsReadOnly: MsPage; + usersPage: MsPage; + organizationPage: MsPage; + myProfilePage: MsPage; userJoinModal: Locator; - createOrgModal: Locator; userGreetModal: Locator; + createOrgModal: Locator; deviceGreetModal: Locator; workspaceSharingModal: Locator; - clientArea: Page; - clientAreaCustomOrder: Page; + clientArea: MsPage; + clientAreaCustomOrder: MsPage; }>({ - home: async ({ page, context }, use) => { + context: async ({ browser }, use) => { + const context = await browser.newContext(); + await use(context); + await context.close(); + }, + + home: async ({ context }, use) => { + const page = await context.newPage(); + page.on('console', (msg) => console.log('> ', msg.text())); await context.grantPermissions(['clipboard-read']); @@ -85,9 +108,34 @@ export const msTest = base.extend<{ await expect(page.locator('#app')).toHaveAttribute('app-state', 'initializing'); await newTestbed(page); + (page as MsPage).userData = generateDefaultUserData(); + (page as MsPage).orgInfo = generateDefaultOrganizationInformation(); await expect(page.locator('#app')).toHaveAttribute('app-state', 'ready'); - await use(page); + await use(page as MsPage); + await dropTestbed(page); + }, + + secondTab: async ({ context }, use) => { + const page = await context.newPage(); + + page.on('console', (msg) => console.log('> ', msg.text())); + await context.grantPermissions(['clipboard-read']); + + await page.addInitScript(() => { + (window as any).TESTING = true; + }); + await page.goto('/'); + await page.waitForLoadState('domcontentloaded'); + + await expect(page.locator('#app')).toHaveAttribute('app-state', 'initializing'); + + await newTestbed(page); + (page as MsPage).userData = generateDefaultUserData(); + (page as MsPage).orgInfo = generateDefaultOrganizationInformation(); + + await expect(page.locator('#app')).toHaveAttribute('app-state', 'ready'); + await use(page as MsPage); await dropTestbed(page); }, @@ -107,20 +155,44 @@ export const msTest = base.extend<{ await use(home); }, - documents: async ({ connected }, use) => { - await connected.locator('.workspaces-container-grid').locator('.workspace-card-item').nth(0).click(); - await expect(connected).toHaveHeader(['The Copper Coronet'], true, true); - await expect(connected).toBeDocumentPage(); - await expect(connected.locator('.folder-container').locator('.no-files-content')).toBeHidden(); + workspaces: async ({ connected }, use) => { + await createWorkspace(connected, 'The Copper Coronet'); + await dismissToast(connected); + await createWorkspace(connected, 'Trademeet'); + await dismissToast(connected); + await createWorkspace(connected, "Watcher's Keep"); + await dismissToast(connected); use(connected); }, - documentsReadOnly: async ({ connected }, use) => { - await connected.locator('.workspaces-container-grid').locator('.workspace-card-item').nth(2).click(); - await expect(connected).toHaveHeader(["Watcher's Keep"], true, true); - await expect(connected).toBeDocumentPage(); - await expect(connected.locator('.folder-container').locator('.no-files-content')).toBeHidden(); - use(connected); + documents: async ({ workspaces }, use, testInfo: TestInfo) => { + await workspaces.locator('.workspaces-container-grid').locator('.workspace-card-item').nth(0).click(); + await expect(workspaces).toHaveHeader(['The Copper Coronet'], true, true); + await expect(workspaces).toBeDocumentPage(); + await expect(workspaces.locator('.folder-container').locator('.no-files')).toBeVisible(); + // Also create a folder here when available + const dropZone = workspaces.locator('.folder-container').locator('.drop-zone').nth(0); + await dragAndDropFile(workspaces, dropZone, [ + path.join(testInfo.config.rootDir, 'data', 'imports', 'image.png'), + path.join(testInfo.config.rootDir, 'data', 'imports', 'document.docx'), + path.join(testInfo.config.rootDir, 'data', 'imports', 'pdfDocument.pdf'), + path.join(testInfo.config.rootDir, 'data', 'imports', 'video.mp4'), + path.join(testInfo.config.rootDir, 'data', 'imports', 'audio.mp3'), + path.join(testInfo.config.rootDir, 'data', 'imports', 'spreadsheet.xlsx'), + path.join(testInfo.config.rootDir, 'data', 'imports', 'text.txt'), + path.join(testInfo.config.rootDir, 'data', 'imports', 'code.py'), + ]); + // Hide the import menu + await workspaces.locator('.upload-menu').locator('.menu-header-icons').locator('ion-icon').nth(1).click(); + use(workspaces); + }, + + documentsReadOnly: async ({ workspaces }, use) => { + await workspaces.locator('.workspaces-container-grid').locator('.workspace-card-item').nth(2).click(); + await expect(workspaces).toHaveHeader(["Watcher's Keep"], true, true); + await expect(workspaces).toBeDocumentPage(); + await expect(workspaces.locator('.folder-container').locator('.no-files-content')).toBeHidden(); + use(workspaces); }, usersPage: async ({ connected }, use) => { @@ -201,15 +273,15 @@ export const msTest = base.extend<{ await use(modal); }, - workspaceSharingModal: async ({ connected }, use) => { - await connected.locator('.workspaces-container-grid').locator('.workspace-card-item').nth(1).locator('.shared-group').click(); - const modal = connected.locator('.workspace-sharing-modal'); + workspaceSharingModal: async ({ workspaces }, use) => { + await workspaces.locator('.workspaces-container-grid').locator('.workspace-card-item').nth(1).locator('.shared-group').click(); + const modal = workspaces.locator('.workspace-sharing-modal'); await expect(modal).toBeVisible(); await use(modal); }, clientArea: async ({ home }, use) => { - UserData.reset(); + home.userData.reset(); await MockBms.mockLogin(home); await MockBms.mockUserRoute(home); await MockBms.mockListOrganizations(home); @@ -234,14 +306,14 @@ export const msTest = base.extend<{ await expect(popover).toBeVisible(); const orgs = popover.locator('.organization-list').getByRole('listitem'); await orgs.nth(0).click(); - await expect(orgSwitchButton).toHaveText(DEFAULT_ORGANIZATION_INFORMATION.name); + await expect(orgSwitchButton).toHaveText(home.orgInfo.name); await expect(popover).toBeHidden(); await use(home); }, clientAreaCustomOrder: async ({ home }, use) => { - UserData.reset(); + home.userData.reset(); await MockBms.mockLogin(home); await MockBms.mockUserRoute(home, { billingSystem: 'CUSTOM_ORDER' }); await MockBms.mockListOrganizations(home); diff --git a/client/tests/e2e/helpers/utils.ts b/client/tests/e2e/helpers/utils.ts index c9baf8bda3f..f322eee6233 100644 --- a/client/tests/e2e/helpers/utils.ts +++ b/client/tests/e2e/helpers/utils.ts @@ -49,13 +49,12 @@ export async function fillIonInput(ionInput: Locator, text: string): Promise<voi export async function fillInputModal(root: Locator | Page, text: string, clear?: boolean): Promise<void> { const modal = root.locator('.text-input-modal'); + await expect(modal).toBeVisible(); if (clear) { await fillIonInput(modal.locator('ion-input'), ''); } const okButton = modal.locator('.ms-modal-footer-buttons').locator('#next-button'); - await expect(okButton).toHaveDisabledAttribute(); await fillIonInput(modal.locator('ion-input'), text); - await expect(okButton).toNotHaveDisabledAttribute(); await okButton.click(); await expect(modal).toBeHidden(); } @@ -189,3 +188,51 @@ export async function sliderClick(page: Page, slider: Locator, progressPercent: await page.mouse.click(box.x + (box.width * progressPercent) / 100, box.y); } } + +export async function workspacesInGridMode(workspacesPage: Page): Promise<boolean> { + return (await workspacesPage.locator('#workspaces-ms-action-bar').locator('#grid-view').getAttribute('disabled')) !== null; +} + +export async function createWorkspace(workspacesPage: Page, name: string): Promise<void> { + let workspacesCount = 0; + const actionBar = workspacesPage.locator('#workspaces-ms-action-bar'); + if (await workspacesInGridMode(workspacesPage)) { + workspacesCount = await workspacesPage.locator('.workspaces-container').locator('.workspace-card-item').count(); + } else { + workspacesCount = await workspacesPage.locator('.workspaces-container').locator('.workspace-list-item').count(); + } + await actionBar.locator('#button-new-workspace').click(); + await fillInputModal(workspacesPage, name); + if (await workspacesInGridMode(workspacesPage)) { + await expect(workspacesPage.locator('.workspaces-container').locator('.workspace-card-item')).toHaveCount(workspacesCount + 1); + } else { + await expect(workspacesPage.locator('.workspaces-container').locator('.workspace-list-item')).toHaveCount(workspacesCount + 1); + } +} + +export async function dismissToast(page: Page): Promise<void> { + await page.locator('.notification-toast').locator('.toast-button-confirm').click(); + await expect(page.locator('.notification-toast')).toBeHidden(); +} + +export function getTestbedBootstrapAddr(orgName: string): string { + const url = new URL(process.env.TESTBED_SERVER ?? ''); + const port = url.port ? `:${url.port}` : ''; + let search = '?a=bootstrap_organization&p=wA'; + + for (const [key, val] of url.searchParams.entries()) { + search = `${search}&${key}=${val}`; + } + return `${url.protocol}//${url.hostname}${port}/${orgName}${search}`; +} + +export function getOrganizationAddr(orgName: string): string { + const url = new URL(process.env.TESTBED_SERVER ?? ''); + const port = url.port ? `:${url.port}` : ''; + + return `${url.protocol}//${url.hostname}${port}/${orgName}${url.search}`; +} + +export function getServerAddr(): string { + return process.env.TESTBED_SERVER ?? ''; +} diff --git a/client/tests/e2e/specs/client_area_dashboard.spec.ts b/client/tests/e2e/specs/client_area_dashboard.spec.ts index 8c479127f49..47dac4f1f85 100644 --- a/client/tests/e2e/specs/client_area_dashboard.spec.ts +++ b/client/tests/e2e/specs/client_area_dashboard.spec.ts @@ -1,6 +1,6 @@ // Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS -import { DEFAULT_ORGANIZATION_INFORMATION, expect, msTest } from '@tests/e2e/helpers'; +import { expect, msTest } from '@tests/e2e/helpers'; msTest('Test dashboard', async ({ clientArea }) => { const title = clientArea.locator('.header-content').locator('.header-title'); @@ -15,19 +15,19 @@ msTest('Test dashboard', async ({ clientArea }) => { await expect(invoices).toHaveCount(3); await expect(invoices.nth(0).locator('.invoices-list-item__data')).toHaveText([ 'Dec 1, 2021', - DEFAULT_ORGANIZATION_INFORMATION.name, + clientArea.orgInfo.name, /^€[\d.,]+$/, /^(Paid|In progress|To pay)\s*Download$/, ]); await expect(invoices.nth(1).locator('.invoices-list-item__data')).toHaveText([ 'Nov 1, 2021', - DEFAULT_ORGANIZATION_INFORMATION.name, + clientArea.orgInfo.name, /^€[\d.,]+$/, /^(Paid|In progress|To pay)\s*Download$/, ]); await expect(invoices.nth(2).locator('.invoices-list-item__data')).toHaveText([ 'Oct 1, 2021', - DEFAULT_ORGANIZATION_INFORMATION.name, + clientArea.orgInfo.name, /^€[\d.,]+$/, /^(Paid|In progress|To pay)\s*Download$/, ]); diff --git a/client/tests/e2e/specs/client_area_invoices_page.spec.ts b/client/tests/e2e/specs/client_area_invoices_page.spec.ts index cf4890174c2..a66f06849c2 100644 --- a/client/tests/e2e/specs/client_area_invoices_page.spec.ts +++ b/client/tests/e2e/specs/client_area_invoices_page.spec.ts @@ -1,6 +1,6 @@ // Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS -import { DEFAULT_ORGANIZATION_INFORMATION, MockBms, expect, msTest } from '@tests/e2e/helpers'; +import { MockBms, expect, msTest } from '@tests/e2e/helpers'; msTest('List the invoices', async ({ clientArea }) => { await MockBms.mockGetInvoices(clientArea); @@ -17,7 +17,7 @@ msTest('List the invoices', async ({ clientArea }) => { await expect(containers.nth(0).locator('.invoices-year-content-list-item').nth(0).locator('ion-text')).toHaveText([ 'Dec 2021', '2021-12', - DEFAULT_ORGANIZATION_INFORMATION.name, + clientArea.orgInfo.name, /^€[\d.,]+$/, /^(Paid|In progress|To pay)\s*Download$/, ]); diff --git a/client/tests/e2e/specs/client_area_login.spec.ts b/client/tests/e2e/specs/client_area_login.spec.ts index 1ba142bf563..8b8ef03377f 100644 --- a/client/tests/e2e/specs/client_area_login.spec.ts +++ b/client/tests/e2e/specs/client_area_login.spec.ts @@ -1,14 +1,6 @@ // Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS -import { - DEFAULT_ORGANIZATION_INFORMATION, - DEFAULT_USER_INFORMATION, - MockBms, - answerQuestion, - expect, - fillIonInput, - msTest, -} from '@tests/e2e/helpers'; +import { DEFAULT_USER_INFORMATION, MockBms, answerQuestion, expect, fillIonInput, msTest } from '@tests/e2e/helpers'; msTest('Log into the customer area', async ({ home }) => { await MockBms.mockLogin(home); @@ -81,8 +73,8 @@ msTest('Switch pages', async ({ clientArea }) => { }); msTest('Switch org', async ({ clientArea }) => { - const org1 = DEFAULT_ORGANIZATION_INFORMATION.name; - const org2 = `${DEFAULT_ORGANIZATION_INFORMATION.name}-2`; + const org1 = clientArea.orgInfo.name; + const org2 = `${clientArea.orgInfo.name}-2`; const orgSwitchButton = clientArea.locator('.sidebar-header').locator('.card-header-title'); await expect(orgSwitchButton).toHaveText(org1); @@ -151,7 +143,7 @@ for (const frozen of [false, true]) { const popover = home.locator('.popover-switch'); const orgs = popover.locator('.organization-list').getByRole('listitem'); await orgs.nth(0).click(); - await expect(orgSwitchButton).toHaveText(DEFAULT_ORGANIZATION_INFORMATION.name); + await expect(orgSwitchButton).toHaveText(home.orgInfo.name); const orgState = home.locator('.sidebar').locator('.sidebar-header').locator('.organization-card-state'); await expect(orgState).toHaveText(frozen ? 'State: Frozen' : 'State: Active'); diff --git a/client/tests/e2e/specs/create_organization_custom.spec.ts b/client/tests/e2e/specs/create_organization_custom.spec.ts index 36c664c9004..fb40ed7ec1c 100644 --- a/client/tests/e2e/specs/create_organization_custom.spec.ts +++ b/client/tests/e2e/specs/create_organization_custom.spec.ts @@ -1,19 +1,7 @@ // Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS import { Locator, Page } from '@playwright/test'; -import { - DEFAULT_ORGANIZATION_INFORMATION, - DEFAULT_USER_INFORMATION, - expect, - fillInputModal, - fillIonInput, - msTest, -} from '@tests/e2e/helpers'; - -/* eslint-disable max-len */ -// cspell:disable-next-line -const BOOTSTRAP_ADDR = `${DEFAULT_ORGANIZATION_INFORMATION.serverAddr}/${DEFAULT_ORGANIZATION_INFORMATION.name}?no_ssl=true&a=bootstrap_organization&p=xBCy2YVGB31DPzcxGZbGVUt7`; -/* eslint-enable max-len */ +import { DEFAULT_USER_INFORMATION, expect, fillInputModal, fillIonInput, getTestbedBootstrapAddr, msTest } from '@tests/e2e/helpers'; async function openCreateOrganizationModal(page: Page): Promise<Locator> { await page.locator('#create-organization-button').click(); @@ -42,10 +30,10 @@ msTest('Go through custom org creation process', async ({ home }) => { const orgNext = orgServerContainer.locator('.organization-name-and-server-page-footer').locator('ion-button').nth(1); await expect(orgPrevious).toBeVisible(); await expect(orgNext).toHaveDisabledAttribute(); - await fillIonInput(orgServerContainer.locator('ion-input').nth(0), DEFAULT_ORGANIZATION_INFORMATION.name); + await fillIonInput(orgServerContainer.locator('ion-input').nth(0), home.orgInfo.name); await expect(orgNext).toHaveDisabledAttribute(); - await fillIonInput(orgServerContainer.locator('ion-input').nth(1), DEFAULT_ORGANIZATION_INFORMATION.serverAddr); - await expect(orgNext).toNotHaveDisabledAttribute(); + await fillIonInput(orgServerContainer.locator('ion-input').nth(1), home.orgInfo.serverAddr); + await expect(orgNext).not.toHaveDisabledAttribute(); // Wrong org name await fillIonInput(orgServerContainer.locator('ion-input').nth(0), 'Invalid Org N@me'); @@ -55,8 +43,8 @@ msTest('Go through custom org creation process', async ({ home }) => { await expect(orgNameError).toHaveText('Only letters, digits, underscores and hyphens. No spaces.'); // Correct org name again - await fillIonInput(orgServerContainer.locator('ion-input').nth(0), DEFAULT_ORGANIZATION_INFORMATION.name); - await expect(orgNext).toNotHaveDisabledAttribute(); + await fillIonInput(orgServerContainer.locator('ion-input').nth(0), home.orgInfo.name); + await expect(orgNext).not.toHaveDisabledAttribute(); await expect(orgNameError).toBeHidden(); // Now wrong server address @@ -67,8 +55,8 @@ msTest('Go through custom org creation process', async ({ home }) => { await expect(orgServerError).toHaveText("Link should start with 'parsec3://'."); // And correct server address again - await fillIonInput(orgServerContainer.locator('ion-input').nth(1), DEFAULT_ORGANIZATION_INFORMATION.serverAddr); - await expect(orgNext).toNotHaveDisabledAttribute(); + await fillIonInput(orgServerContainer.locator('ion-input').nth(1), home.orgInfo.serverAddr); + await expect(orgNext).not.toHaveDisabledAttribute(); await expect(orgServerError).toBeHidden(); await orgNext.click(); @@ -186,7 +174,7 @@ msTest('Go through custom org creation process', async ({ home }) => { 'Authentication method', ]); await expect(summaryContainer.locator('.summary-item__text')).toHaveText([ - DEFAULT_ORGANIZATION_INFORMATION.name, + home.orgInfo.name, DEFAULT_USER_INFORMATION.name, DEFAULT_USER_INFORMATION.email, 'Custom Server', @@ -208,10 +196,10 @@ msTest('Go through custom org creation process', async ({ home }) => { await expect(modal).toBeHidden(); }); -msTest('Go through custom org creation process from bootstrap link', async ({ home }) => { +msTest.skip('Go through custom org creation process from bootstrap link', async ({ home }) => { await home.locator('#create-organization-button').click(); await home.locator('.popover-viewport').getByRole('listitem').nth(1).click(); - await fillInputModal(home, BOOTSTRAP_ADDR); + await fillInputModal(home, getTestbedBootstrapAddr(home.orgInfo.name)); const modal = home.locator('.create-organization-modal'); const orgServerContainer = modal.locator('.organization-name-and-server-page'); @@ -222,11 +210,9 @@ msTest('Go through custom org creation process from bootstrap link', async ({ ho await expect(orgNext).toNotHaveDisabledAttribute(); await expect(orgServerContainer.locator('ion-input').nth(0)).toHaveTheClass('input-disabled'); - await expect(orgServerContainer.locator('ion-input').nth(0).locator('input')).toHaveValue(DEFAULT_ORGANIZATION_INFORMATION.name); + await expect(orgServerContainer.locator('ion-input').nth(0).locator('input')).toHaveValue(home.orgInfo.name); await expect(orgServerContainer.locator('ion-input').nth(1)).toHaveTheClass('input-disabled'); - await expect(orgServerContainer.locator('ion-input').nth(1).locator('input')).toHaveValue( - `${DEFAULT_ORGANIZATION_INFORMATION.serverAddr}:80`, - ); + await expect(orgServerContainer.locator('ion-input').nth(1).locator('input')).toHaveValue(`${home.orgInfo.serverAddr}`); await orgNext.click(); const userInfoContainer = modal.locator('.user-information-page'); @@ -290,7 +276,7 @@ msTest('Go through custom org creation process from bootstrap link', async ({ ho 'Authentication method', ]); await expect(summaryContainer.locator('.summary-item__text')).toHaveText([ - DEFAULT_ORGANIZATION_INFORMATION.name, + home.orgInfo.name, DEFAULT_USER_INFORMATION.name, DEFAULT_USER_INFORMATION.email, 'Custom Server', diff --git a/client/tests/e2e/specs/create_organization_saas.spec.ts b/client/tests/e2e/specs/create_organization_saas.spec.ts index bab82e1df42..2f79dd213b0 100644 --- a/client/tests/e2e/specs/create_organization_saas.spec.ts +++ b/client/tests/e2e/specs/create_organization_saas.spec.ts @@ -2,21 +2,15 @@ import { Locator, Page } from '@playwright/test'; import { - DEFAULT_ORGANIZATION_INFORMATION, DEFAULT_USER_INFORMATION, MockBms, expect, fillInputModal, fillIonInput, + getTestbedBootstrapAddr, msTest, } from '@tests/e2e/helpers'; -// cspell:disable-next-line -const _HOST = 'saas-demo-v3-mightyfairy.parsec.cloud'; -// cspell:disable-next-line -const _PAYLOAD = 'xBCy2YVGB31DPzcxGZbGVUt7'; -const BOOTSTRAP_ADDR = `parsec3://${_HOST}/BlackMesa?no_ssl=true&a=bootstrap_organization&p=${_PAYLOAD}`; - async function openCreateOrganizationModal(page: Page): Promise<Locator> { await page.locator('#create-organization-button').click(); await page.locator('.popover-viewport').getByRole('listitem').nth(0).click(); @@ -41,7 +35,7 @@ msTest('Go through saas org creation process', async ({ home }) => { await MockBms.mockLogin(home); await MockBms.mockUserRoute(home); - await MockBms.mockCreateOrganization(home, BOOTSTRAP_ADDR); + await MockBms.mockCreateOrganization(home, getTestbedBootstrapAddr(home.orgInfo.name)); const bmsContainer = modal.locator('.saas-login'); await expect(bmsContainer.locator('.modal-header-title__text')).toHaveText('Link your customer account to your new organization'); @@ -72,7 +66,7 @@ msTest('Go through saas org creation process', async ({ home }) => { await expect(orgNameError).toHaveText('Only letters, digits, underscores and hyphens. No spaces.'); // Back to good name - await fillIonInput(orgNameContainer.locator('ion-input'), DEFAULT_ORGANIZATION_INFORMATION.name); + await fillIonInput(orgNameContainer.locator('ion-input'), home.orgInfo.name); await expect(orgNameError).toBeHidden(); await expect(orgNameNext).toNotHaveDisabledAttribute(); @@ -151,7 +145,7 @@ msTest('Go through saas org creation process', async ({ home }) => { 'Authentication method', ]); await expect(summaryContainer.locator('.summary-item__text')).toHaveText([ - DEFAULT_ORGANIZATION_INFORMATION.name, + home.orgInfo.name, DEFAULT_USER_INFORMATION.name, DEFAULT_USER_INFORMATION.email, 'Parsec SaaS', @@ -206,7 +200,8 @@ for (const testInfo of [ status: testInfo.status, }; } - await MockBms.mockCreateOrganization(home, BOOTSTRAP_ADDR, { POST: routeOptions }); + + await MockBms.mockCreateOrganization(home, getTestbedBootstrapAddr(home.orgInfo.name), { POST: routeOptions }); const bmsContainer = modal.locator('.saas-login'); const bmsNext = bmsContainer.locator('.saas-login-button').locator('.saas-login-button__item').nth(1); @@ -216,7 +211,7 @@ for (const testInfo of [ const orgNameContainer = modal.locator('.organization-name-page'); const orgNameNext = modal.locator('.organization-name-page-footer').locator('ion-button').nth(1); - await fillIonInput(orgNameContainer.locator('ion-input'), DEFAULT_ORGANIZATION_INFORMATION.name); + await fillIonInput(orgNameContainer.locator('ion-input'), home.orgInfo.name); await orgNameNext.click(); const authContainer = modal.locator('.authentication-page'); @@ -238,12 +233,12 @@ for (const testInfo of [ msTest('Go through saas org creation process from bootstrap link', async ({ home }) => { await home.locator('#create-organization-button').click(); await home.locator('.popover-viewport').getByRole('listitem').nth(1).click(); - await fillInputModal(home, BOOTSTRAP_ADDR); + await fillInputModal(home, getTestbedBootstrapAddr(home.orgInfo.name)); const modal = home.locator('.create-organization-modal'); await MockBms.mockLogin(home); await MockBms.mockUserRoute(home); - await MockBms.mockCreateOrganization(home, BOOTSTRAP_ADDR); + await MockBms.mockCreateOrganization(home, getTestbedBootstrapAddr(home.orgInfo.name)); const bmsContainer = modal.locator('.saas-login'); await expect(bmsContainer.locator('.modal-header-title__text')).toHaveText('Link your customer account to your new organization'); @@ -302,7 +297,7 @@ msTest('Go through saas org creation process from bootstrap link', async ({ home 'Authentication method', ]); await expect(summaryContainer.locator('.summary-item__text')).toHaveText([ - DEFAULT_ORGANIZATION_INFORMATION.name, + home.orgInfo.name, DEFAULT_USER_INFORMATION.name, DEFAULT_USER_INFORMATION.email, 'Parsec SaaS', @@ -371,7 +366,7 @@ msTest('Edit from summary', async ({ home }) => { await MockBms.mockLogin(home); await MockBms.mockUserRoute(home); - await MockBms.mockCreateOrganization(home, BOOTSTRAP_ADDR); + await MockBms.mockCreateOrganization(home, getTestbedBootstrapAddr(home.orgInfo.name)); const bmsContainer = modal.locator('.saas-login'); const bmsNext = bmsContainer.locator('.saas-login-button').locator('.saas-login-button__item').nth(1); @@ -381,7 +376,7 @@ msTest('Edit from summary', async ({ home }) => { const orgNameContainer = modal.locator('.organization-name-page'); const orgNameNext = modal.locator('.organization-name-page-footer').locator('ion-button').nth(1); - await fillIonInput(orgNameContainer.locator('ion-input'), DEFAULT_ORGANIZATION_INFORMATION.name); + await fillIonInput(orgNameContainer.locator('ion-input'), home.orgInfo.name); await orgNameNext.click(); const authContainer = modal.locator('.authentication-page'); @@ -401,7 +396,7 @@ msTest('Edit from summary', async ({ home }) => { 'Authentication method', ]); await expect(summaryContainer.locator('.summary-item__text')).toHaveText([ - DEFAULT_ORGANIZATION_INFORMATION.name, + home.orgInfo.name, DEFAULT_USER_INFORMATION.name, DEFAULT_USER_INFORMATION.email, 'Parsec SaaS', @@ -414,7 +409,7 @@ msTest('Edit from summary', async ({ home }) => { await expect(summaryContainer).toBeHidden(); await expect(orgNameContainer).toBeVisible(); - await fillIonInput(orgNameContainer.locator('ion-input'), `${DEFAULT_ORGANIZATION_INFORMATION.name}2`); + await fillIonInput(orgNameContainer.locator('ion-input'), `${home.orgInfo.name}-2`); await orgNameNext.click(); await authNext.click(); @@ -422,7 +417,7 @@ msTest('Edit from summary', async ({ home }) => { await expect(summaryContainer).toBeVisible(); await expect(orgNameContainer).toBeHidden(); await expect(summaryContainer.locator('.summary-item__text')).toHaveText([ - `${DEFAULT_ORGANIZATION_INFORMATION.name}2`, + `${home.orgInfo.name}-2`, DEFAULT_USER_INFORMATION.name, DEFAULT_USER_INFORMATION.email, 'Parsec SaaS', diff --git a/client/tests/e2e/specs/create_organization_trial.spec.ts b/client/tests/e2e/specs/create_organization_trial.spec.ts index 692a96f2ff0..0b7ebb286ad 100644 --- a/client/tests/e2e/specs/create_organization_trial.spec.ts +++ b/client/tests/e2e/specs/create_organization_trial.spec.ts @@ -1,19 +1,7 @@ // Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS import { Locator, Page } from '@playwright/test'; -import { - DEFAULT_ORGANIZATION_INFORMATION, - DEFAULT_USER_INFORMATION, - expect, - fillInputModal, - fillIonInput, - msTest, -} from '@tests/e2e/helpers'; - -/* eslint-disable max-len */ -// cspell:disable-next-line -const BOOTSTRAP_ADDR = `parsec3://trial.parsec.cloud/${DEFAULT_ORGANIZATION_INFORMATION.name}?no_ssl=true&a=bootstrap_organization&p=xBCy2YVGB31DPzcxGZbGVUt7`; -/* eslint-enable max-len */ +import { DEFAULT_USER_INFORMATION, expect, fillInputModal, fillIonInput, getTestbedBootstrapAddr, msTest } from '@tests/e2e/helpers'; async function openCreateOrganizationModal(page: Page): Promise<Locator> { await page.locator('#create-organization-button').click(); @@ -136,7 +124,7 @@ msTest('Go through trial org creation process', async ({ home }) => { msTest('Go through trial org creation process from bootstrap link', async ({ home }) => { await home.locator('#create-organization-button').click(); await home.locator('.popover-viewport').getByRole('listitem').nth(1).click(); - await fillInputModal(home, BOOTSTRAP_ADDR); + await fillInputModal(home, getTestbedBootstrapAddr('CustomOrg')); const modal = home.locator('.create-organization-modal'); const userInfoContainer = modal.locator('.user-information-page'); diff --git a/client/tests/e2e/specs/device_greet.spec.ts b/client/tests/e2e/specs/device_greet.spec.ts index 90c64f9b6bb..3ce319643e8 100644 --- a/client/tests/e2e/specs/device_greet.spec.ts +++ b/client/tests/e2e/specs/device_greet.spec.ts @@ -1,99 +1,416 @@ // Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS -import { answerQuestion, expect, msTest } from '@tests/e2e/helpers'; +import { Locator, Page } from '@playwright/test'; +import { + answerQuestion, + expect, + fillInputModal, + fillIonInput, + getClipboardText, + msTest, + setWriteClipboardPermission, +} from '@tests/e2e/helpers'; -msTest('Open the greet device modal', async ({ deviceGreetModal }) => { - await expect(deviceGreetModal.locator('.modal-header__title')).toHaveText('Create a new device'); - await expect(deviceGreetModal.locator('#next-button')).toHaveText('Start'); - await expect(deviceGreetModal.locator('.closeBtn')).toBeVisible(); +interface ModalData { + modal: Locator; + nextButton: Locator; + title: Locator; + subtitle: Locator; + content: Locator; + closeButton: Locator; +} + +async function initModals(hostPage: Page, guestPage: Page): Promise<[ModalData, ModalData]> { + // Invite a new user and retrieve the invitation link + await hostPage.locator('.devices-header').locator('#add-device-button').click(); + const greetModal = hostPage.locator('.greet-organization-modal'); + // cspell:disable-next-line + await expect(greetModal.locator('.modal-header__title')).toHaveText('Create a new device'); + await expect(greetModal.locator('.first-step').locator('.container-textinfo__text')).toHaveText( + 'Parsec must be open on both devices during the onboarding process.', + ); + await expect(greetModal.locator('#next-button')).toHaveText('Start'); + await expect(greetModal.locator('.closeBtn')).toBeVisible(); + + await setWriteClipboardPermission(hostPage.context(), true); + await greetModal.locator('#copy-link-btn').click(); + await expect(hostPage).toShowToast('Invitation link has been copied to clipboard.', 'Info'); + const invitationLink = await getClipboardText(hostPage); + + // Use the invitation link in the second tab + await guestPage.locator('#create-organization-button').click(); + await expect(guestPage.locator('.homepage-popover')).toBeVisible(); + await guestPage.locator('.homepage-popover').getByRole('listitem').nth(1).click(); + await fillInputModal(guestPage, invitationLink); + const joinModal = guestPage.locator('.join-organization-modal'); + await expect(joinModal).toBeVisible(); + + const greetData = { + modal: greetModal, + nextButton: greetModal.locator('#next-button'), + title: greetModal.locator('.modal-header__title'), + subtitle: greetModal.locator('.modal-header__text'), + content: greetModal.locator('.modal-content'), + closeButton: greetModal.locator('.closeBtn'), + }; + // Start the greet + await expect(greetData.title).toHaveText('Create a new device'); + await expect(greetData.nextButton).toHaveText('Start'); + await greetData.nextButton.click(); + + const joinData = { + modal: joinModal, + nextButton: joinModal.locator('#next-button'), + title: joinModal.locator('.modal-header__title'), + subtitle: joinModal.locator('.modal-header__text'), + content: joinModal.locator('.modal-content'), + closeButton: joinModal.locator('.closeBtn'), + }; + + // Start the join + await expect(joinData.title).toHaveText('Add a new device'); + await expect(joinData.nextButton).toHaveText('I understand!'); + await joinData.nextButton.click(); + + return [greetData, joinData]; +} + +msTest('Greet device whole process', async ({ myProfilePage, secondTab }) => { + // Very slow test since it syncs the greet and join + msTest.setTimeout(120_000); + + const [greetData, joinData] = await initModals(myProfilePage, secondTab); + + // Check the provide code page from the host and retrieve the code + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code'], 0); + await expect(greetData.title).toHaveText('Share your code'); + await expect(greetData.subtitle).toHaveText('Click on the code below on the guest device.'); + const greetCode = (await greetData.content.locator('.host-code').locator('.code').textContent()) ?? ''; + expect(greetCode).toMatch(/^[A-Z0-9]{4}$/); + + // Check the enter code page from the guest and select the code + await expect(joinData.title).toHaveText('Get host code'); + await expect(joinData.subtitle).toHaveText('Click on the code you see on the main device.'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Authentication'], 0); + await expect(joinData.content.locator('.button-choice')).toHaveCount(4); + await joinData.content.locator('.button-choice', { hasText: greetCode }).click(); + + // Check the provide code page from the guest and retrieve the code + await expect(joinData.title).toHaveText('Share guest code'); + await expect(joinData.subtitle).toHaveText('On the main device, click on the code you see below.'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Authentication'], 1); + const joinCode = (await joinData.content.locator('.guest-code').locator('.code').textContent()) ?? ''; + expect(joinCode).toMatch(/^[A-Z0-9]{4}$/); + + // Check the enter code page from the host and select the code + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code'], 1); + await expect(greetData.title).toHaveText('Get guest code'); + await expect(greetData.subtitle).toHaveText('Click on the code that appears on the guest device.'); + await expect(greetData.content.locator('.button-choice')).toHaveCount(4); + await greetData.content.locator('.button-choice', { hasText: joinCode }).click(); + + // Host waits for guest to choose auth + await expect(greetData.title).toHaveText('Waiting for device information'); + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code'], 1); + await expect(greetData.nextButton).toBeHidden(); + + // Guest choose auth + await expect(joinData.title).toHaveText('Authentication'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Authentication'], 2); + await expect(joinData.nextButton).toHaveText('Confirm'); + await expect(joinData.nextButton).toHaveDisabledAttribute(); + + const authRadio = joinData.content.locator('.choose-auth-page').locator('.radio-list-item'); + await expect(authRadio).toHaveCount(2); + await expect(authRadio.nth(0)).toHaveTheClass('radio-disabled'); + await expect(authRadio.nth(0).locator('.item-radio__label')).toHaveText('Use System Authentication'); + await expect(authRadio.nth(0).locator('.item-radio__text:visible')).toHaveText('Unavailable on web'); + await expect(authRadio.nth(1)).toHaveText('Use Password'); + const passwordChoice = joinData.content.locator('#get-password').locator('.choose-password'); + await passwordChoice.scrollIntoViewIfNeeded(); + await fillIonInput(passwordChoice.locator('ion-input').nth(0), 'AVeryL0ngP@ssw0rd'); + await expect(joinData.nextButton).toHaveDisabledAttribute(); + await fillIonInput(passwordChoice.locator('ion-input').nth(1), 'AVeryL0ngP@ssw0rd'); + await joinData.nextButton.scrollIntoViewIfNeeded(); + await expect(joinData.nextButton).not.toHaveDisabledAttribute(); + await joinData.nextButton.click(); + await expect(joinData.title).toHaveText('Device has been added!'); + await expect(joinData.modal.locator('.final-step').locator('.container-textinfo__text')).toHaveText( + 'The device has been created and added to this organization. You can now use it to connect to Parsec.', + ); + await expect(joinData.nextButton).toHaveText('Log in'); + await expect(joinData.nextButton).not.toHaveDisabledAttribute(); + await joinData.nextButton.click(); + await expect(joinData.modal).toBeHidden(); + await expect(secondTab).toShowToast('You can now access your organization from your new device.', 'Success'); + // Automatically logged in + await expect(secondTab.locator('#connected-header')).toContainText('My workspaces'); + await expect(secondTab).toBeWorkspacePage(); + const profile = secondTab.locator('.topbar').locator('.profile-header'); + await expect(profile.locator('.text-content-name')).toHaveText('Alicey McAliceFace'); + + // host is done + await expect(greetData.title).toHaveText('New device added'); + await expect(greetData.subtitle).toHaveText('The device Web has been added to your profile.'); + await expect(greetData.nextButton).toHaveText('Finish'); + await expect(greetData.nextButton).not.toHaveDisabledAttribute(); + await expect(greetData.nextButton).toBeVisible(); + await expect(greetData.content.locator('.final-step').locator('.device-name')).toHaveText('Web'); + await expect(greetData.content.locator('.final-step').locator('.join-date')).toHaveText('Joined: Today'); + await greetData.nextButton.click(); + await expect(greetData.modal).toBeHidden(); + await expect(myProfilePage).toShowToast('You can connect to this organization from your new device.', 'Success'); }); -msTest('Go through the greet process', async ({ deviceGreetModal }) => { - const title = deviceGreetModal.locator('.modal-header__title'); - const subtitle = deviceGreetModal.locator('.modal-header__text'); - const nextButton = deviceGreetModal.locator('#next-button'); - const modalContent = deviceGreetModal.locator('.modal-content'); - - await nextButton.click(); - - await expect(deviceGreetModal).toHaveWizardStepper(['Host code', 'Guest code'], 0); - - await expect(title).toHaveText('Share your code'); - await expect(subtitle).toHaveText('Click on the code that appears on the guest device.'); - await expect(nextButton).toBeHidden(); - await deviceGreetModal.page().waitForTimeout(200); - - await expect(deviceGreetModal).toHaveWizardStepper(['Host code', 'Guest code'], 1); - await expect(title).toHaveText('Get guest code'); - await expect(subtitle).toHaveText('Click on the code that appears on the guest device.'); - const choices = modalContent.locator('.code:visible'); - await expect(choices).toHaveText(['1ABC', '2DEF', '3GHI', '4JKL']); - await expect(nextButton).toBeHidden(); - await choices.nth(1).click(); - - await expect(title).toHaveText('Waiting for device information'); - await expect(deviceGreetModal).toHaveWizardStepper(['Host code', 'Guest code'], 1); - await expect(nextButton).toBeHidden(); - await deviceGreetModal.page().waitForTimeout(200); - - await expect(title).toHaveText('New device added'); - await expect(nextButton).toNotHaveDisabledAttribute(); - await expect(nextButton).toBeVisible(); - await expect(nextButton).toHaveText('Finish'); - await nextButton.click(); - - await expect(deviceGreetModal.page().locator('.greet-organization-modal')).toBeHidden(); - await expect(deviceGreetModal.page()).toShowToast('You can connect to this organization from your new device.', 'Success'); +msTest('Host selects invalid SAS code', async ({ myProfilePage, secondTab }) => { + // Very slow test since it syncs the greet and join + msTest.setTimeout(120_000); + + const [greetData, joinData] = await initModals(myProfilePage, secondTab); + + // Check the provide code page from the host and retrieve the code + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code'], 0); + await expect(greetData.title).toHaveText('Share your code'); + await expect(greetData.subtitle).toHaveText('Click on the code below on the guest device.'); + const greetCode = (await greetData.content.locator('.host-code').locator('.code').textContent()) ?? ''; + expect(greetCode).toMatch(/^[A-Z0-9]{4}$/); + + // Check the enter code page from the guest and select the code + await expect(joinData.title).toHaveText('Get host code'); + await expect(joinData.subtitle).toHaveText('Click on the code you see on the main device.'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Authentication'], 0); + await expect(joinData.content.locator('.button-choice')).toHaveCount(4); + await joinData.content.locator('.button-choice', { hasText: greetCode }).click(); + + // Check the provide code page from the guest and retrieve the code + await expect(joinData.title).toHaveText('Share guest code'); + await expect(joinData.subtitle).toHaveText('On the main device, click on the code you see below.'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Authentication'], 1); + const joinCode = (await joinData.content.locator('.guest-code').locator('.code').textContent()) ?? ''; + expect(joinCode).toMatch(/^[A-Z0-9]{4}$/); + + // Check the enter code page from the host and select an invalid code + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code'], 1); + await expect(greetData.title).toHaveText('Get guest code'); + await expect(greetData.subtitle).toHaveText('Click on the code that appears on the guest device.'); + await expect(greetData.content.locator('.button-choice')).toHaveCount(4); + await greetData.content.locator('.button-choice', { hasNotText: joinCode }).nth(0).click(); + + await expect(secondTab).toShowToast('The code selected on the other device is incorrect.', 'Error'); + await expect(myProfilePage).toShowToast('You did not select the correct code. Please restart the onboarding process.', 'Error'); + + // Back to the beginning + await expect(greetData.nextButton).toHaveText('Start'); + await expect(greetData.title).toHaveText('Create a new device'); + + await expect(joinData.title).toHaveText('Add a new device'); + await expect(joinData.nextButton).toHaveText('I understand!'); }); -msTest('Device greet select invalid SAS code', async ({ deviceGreetModal }) => { - const title = deviceGreetModal.locator('.modal-header__title'); - const nextButton = deviceGreetModal.locator('#next-button'); - await nextButton.click(); +msTest('Host selects no SAS code', async ({ myProfilePage, secondTab }) => { + // Very slow test since it syncs the greet and join + msTest.setTimeout(120_000); + + const [greetData, joinData] = await initModals(myProfilePage, secondTab); + + // Check the provide code page from the host and retrieve the code + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code'], 0); + await expect(greetData.title).toHaveText('Share your code'); + await expect(greetData.subtitle).toHaveText('Click on the code below on the guest device.'); + const greetCode = (await greetData.content.locator('.host-code').locator('.code').textContent()) ?? ''; + expect(greetCode).toMatch(/^[A-Z0-9]{4}$/); - await expect(title).toHaveText('Get guest code'); - const choices = deviceGreetModal.locator('.modal-content').locator('.code:visible'); - await choices.nth(0).click(); + // Check the enter code page from the guest and select the code + await expect(joinData.title).toHaveText('Get host code'); + await expect(joinData.subtitle).toHaveText('Click on the code you see on the main device.'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Authentication'], 0); + await expect(joinData.content.locator('.button-choice')).toHaveCount(4); + await joinData.content.locator('.button-choice', { hasText: greetCode }).click(); - await expect(deviceGreetModal.page()).toShowToast('You did not select the correct code. Please restart the onboarding process.', 'Error'); - await expect(title).toHaveText('Create a new device'); + // Check the provide code page from the guest and retrieve the code + await expect(joinData.title).toHaveText('Share guest code'); + await expect(joinData.subtitle).toHaveText('On the main device, click on the code you see below.'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Authentication'], 1); + const joinCode = (await joinData.content.locator('.guest-code').locator('.code').textContent()) ?? ''; + expect(joinCode).toMatch(/^[A-Z0-9]{4}$/); + + // Check the enter code page from the host and select none of the codes + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code'], 1); + await expect(greetData.title).toHaveText('Get guest code'); + await expect(greetData.subtitle).toHaveText('Click on the code that appears on the guest device.'); + await expect(greetData.content.locator('.button-none')).toHaveText('None shown'); + await greetData.content.locator('.button-none').click(); + + await expect(secondTab).toShowToast('The process has been cancelled from the other device.', 'Error'); + await expect(myProfilePage).toShowToast( + 'If you did not see the correct code, this could be a sign of a security issue during the onboarding. Please restart the process.', + 'Error', + ); + + // Back to the beginning + await expect(greetData.nextButton).toHaveText('Start'); + await expect(greetData.title).toHaveText('Create a new device'); + + await expect(joinData.title).toHaveText('Add a new device'); + await expect(joinData.nextButton).toHaveText('I understand!'); +}); + +msTest('Host closes greet process', async ({ myProfilePage, secondTab }) => { + // Very slow test since it syncs the greet and join + msTest.setTimeout(120_000); + + const [greetData, joinData] = await initModals(myProfilePage, secondTab); + + // Check the provide code page from the host and retrieve the code + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code'], 0); + await expect(greetData.title).toHaveText('Share your code'); + await expect(greetData.subtitle).toHaveText('Click on the code below on the guest device.'); + const greetCode = (await greetData.content.locator('.host-code').locator('.code').textContent()) ?? ''; + expect(greetCode).toMatch(/^[A-Z0-9]{4}$/); + + // Check the enter code page from the guest and select the code + await expect(joinData.title).toHaveText('Get host code'); + await expect(joinData.subtitle).toHaveText('Click on the code you see on the main device.'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Authentication'], 0); + await expect(joinData.content.locator('.button-choice')).toHaveCount(4); + await joinData.content.locator('.button-choice', { hasText: greetCode }).click(); + + // Check the provide code page from the guest and retrieve the code + await expect(joinData.title).toHaveText('Share guest code'); + await expect(joinData.subtitle).toHaveText('On the main device, click on the code you see below.'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Authentication'], 1); + const joinCode = (await joinData.content.locator('.guest-code').locator('.code').textContent()) ?? ''; + expect(joinCode).toMatch(/^[A-Z0-9]{4}$/); + + // Check the enter code page from the host and try to close but cancel + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code'], 1); + await expect(greetData.title).toHaveText('Get guest code'); + await expect(greetData.subtitle).toHaveText('Click on the code that appears on the guest device.'); + await greetData.closeButton.click(); + await answerQuestion(myProfilePage, false, { + expectedTitleText: 'Cancel', + expectedQuestionText: 'Are you sure you want to cancel the onboarding process?', + expectedPositiveText: 'Cancel process', + expectedNegativeText: 'Resume', + }); + + // Now cancel it for real + await greetData.closeButton.click(); + await answerQuestion(myProfilePage, true, { + expectedTitleText: 'Cancel', + expectedQuestionText: 'Are you sure you want to cancel the onboarding process?', + expectedPositiveText: 'Cancel process', + expectedNegativeText: 'Resume', + }); + await expect(greetData.modal).toBeHidden(); + + // Check that guest is notified and can restart + await expect(secondTab).toShowToast('The process has been cancelled from the other device.', 'Error'); + await expect(joinData.title).toHaveText('Add a new device'); + await expect(joinData.nextButton).toHaveText('I understand!'); +}); + +msTest('Guest selects invalid SAS code', async ({ myProfilePage, secondTab }) => { + // Very slow test since it syncs the greet and join + msTest.setTimeout(120_000); + + const [greetData, joinData] = await initModals(myProfilePage, secondTab); + + // Check the provide code page from the host and retrieve the code + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code'], 0); + await expect(greetData.title).toHaveText('Share your code'); + await expect(greetData.subtitle).toHaveText('Click on the code below on the guest device.'); + const greetCode = (await greetData.content.locator('.host-code').locator('.code').textContent()) ?? ''; + expect(greetCode).toMatch(/^[A-Z0-9]{4}$/); + + // Check the enter code page from the guest and select an invalid code + await expect(joinData.title).toHaveText('Get host code'); + await expect(joinData.subtitle).toHaveText('Click on the code you see on the main device.'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Authentication'], 0); + await expect(joinData.content.locator('.button-choice')).toHaveCount(4); + await joinData.content.locator('.button-choice', { hasNotText: greetCode }).nth(0).click(); + + await expect(secondTab).toShowToast('You did not select the correct code. Please restart the onboarding process.', 'Error'); + await expect(myProfilePage).toShowToast('The code selected on the other device is incorrect.', 'Error'); + + // Back to the beginning + await expect(greetData.nextButton).toHaveText('Start'); + await expect(greetData.title).toHaveText('Create a new device'); + + await expect(joinData.title).toHaveText('Add a new device'); + await expect(joinData.nextButton).toHaveText('I understand!'); }); -msTest('Device greet select no SAS code', async ({ deviceGreetModal }) => { - const title = deviceGreetModal.locator('.modal-header__title'); - const nextButton = deviceGreetModal.locator('#next-button'); - await nextButton.click(); +msTest('Guest selects no SAS code', async ({ myProfilePage, secondTab }) => { + // Very slow test since it syncs the greet and join + msTest.setTimeout(120_000); - await expect(title).toHaveText('Get guest code'); - await deviceGreetModal.locator('.modal-content').locator('.button-none').click(); + const [greetData, joinData] = await initModals(myProfilePage, secondTab); - await expect(deviceGreetModal.page()).toShowToast( + // Check the provide code page from the host and retrieve the code + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code'], 0); + await expect(greetData.title).toHaveText('Share your code'); + await expect(greetData.subtitle).toHaveText('Click on the code below on the guest device.'); + const greetCode = (await greetData.content.locator('.host-code').locator('.code').textContent()) ?? ''; + expect(greetCode).toMatch(/^[A-Z0-9]{4}$/); + + // Check the enter code page from the guest and select none of the codes + await expect(joinData.title).toHaveText('Get host code'); + await expect(joinData.subtitle).toHaveText('Click on the code you see on the main device.'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Authentication'], 0); + await joinData.content.locator('.button-none').click(); + + await expect(secondTab).toShowToast( 'If you did not see the correct code, this could be a sign of a security issue during the onboarding. Please restart the process.', 'Error', ); - await expect(title).toHaveText('Create a new device'); + await expect(myProfilePage).toShowToast('The process has been cancelled from the other device.', 'Error'); + + // Back to the beginning + await expect(greetData.nextButton).toHaveText('Start'); + await expect(greetData.title).toHaveText('Create a new device'); + + await expect(joinData.title).toHaveText('Add a new device'); + await expect(joinData.nextButton).toHaveText('I understand!'); }); -for (const cancel of [true, false]) { - msTest(`Try closing device greet process${cancel ? ' and cancel' : ''}`, async ({ deviceGreetModal }) => { - const title = deviceGreetModal.locator('.modal-header__title'); - const nextButton = deviceGreetModal.locator('#next-button'); - const closeButton = deviceGreetModal.locator('.closeBtn'); - - await nextButton.click(); - await expect(title).toHaveText('Get guest code'); - - await closeButton.click(); - await answerQuestion(deviceGreetModal.page(), !cancel, { - expectedTitleText: 'Cancel', - expectedQuestionText: 'Are you sure you want to cancel the onboarding process?', - expectedPositiveText: 'Cancel process', - expectedNegativeText: 'Resume', - }); - if (cancel) { - await expect(deviceGreetModal.page().locator('.greet-organization-modal')).toBeVisible(); - } else { - await expect(deviceGreetModal.page().locator('.greet-organization-modal')).toBeHidden(); - } +msTest('Guest closes greet process', async ({ myProfilePage, secondTab }) => { + // Very slow test since it syncs the greet and join + msTest.setTimeout(120_000); + + const [greetData, joinData] = await initModals(myProfilePage, secondTab); + + // Check the provide code page from the host and retrieve the code + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code'], 0); + await expect(greetData.title).toHaveText('Share your code'); + await expect(greetData.subtitle).toHaveText('Click on the code below on the guest device.'); + const greetCode = (await greetData.content.locator('.host-code').locator('.code').textContent()) ?? ''; + expect(greetCode).toMatch(/^[A-Z0-9]{4}$/); + + // Check the enter code page from the guest and try to close but cancel + await expect(joinData.title).toHaveText('Get host code'); + await expect(joinData.subtitle).toHaveText('Click on the code you see on the main device.'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Authentication'], 0); + await joinData.closeButton.click(); + await answerQuestion(secondTab, false, { + expectedTitleText: 'Cancel the process', + expectedQuestionText: 'Are you sure you want to cancel the process? Information will not be saved, you will have to restart.', + expectedPositiveText: 'Cancel process', + expectedNegativeText: 'Resume', }); -} + + // Now cancel it for real + await joinData.closeButton.click(); + await answerQuestion(secondTab, true, { + expectedTitleText: 'Cancel the process', + expectedQuestionText: 'Are you sure you want to cancel the process? Information will not be saved, you will have to restart.', + expectedPositiveText: 'Cancel process', + expectedNegativeText: 'Resume', + }); + await expect(joinData.modal).toBeHidden(); + + // Check that host is notified and can restart + await expect(myProfilePage).toShowToast('The process has been cancelled from the other device.', 'Error'); + await expect(greetData.title).toHaveText('Create a new device'); + await expect(greetData.nextButton).toHaveText('Start'); +}); diff --git a/client/tests/e2e/specs/device_join_organization.spec.ts b/client/tests/e2e/specs/device_join_organization.spec.ts deleted file mode 100644 index 095067b6318..00000000000 --- a/client/tests/e2e/specs/device_join_organization.spec.ts +++ /dev/null @@ -1,83 +0,0 @@ -// Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS - -import { Locator } from '@playwright/test'; -import { expect, fillIonInput, msTest } from '@tests/e2e/helpers'; - -// cspell:disable-next-line -const INVITATION_LINK = 'parsec3://parsec.cloud/Test?a=claim_device&p=xBBHJlEjlpxNZYTCvBWWDPIS'; -const WAIT_TIME = 1000; - -msTest('Claim device process', async ({ home }) => { - async function checkStepper(steps: Locator, activeIndex: number): Promise<void> { - for (let i = 0; i < 2; i++) { - if (i < activeIndex) { - expect(steps.nth(i).locator('.circle').locator('.inner-circle-done')).toBeDefined(); - } else if (i === activeIndex) { - expect(steps.nth(i).locator('.circle').locator('.inner-circle-active')).toBeDefined(); - } else { - expect(steps.nth(i).locator('.circle').locator('.inner-circle-active').locator('div')).toHaveCount(0); - } - } - } - - const modal = home.locator('.join-organization-modal'); - await expect(modal).toBeHidden(); - - await home.locator('#create-organization-button').click(); - await home.locator('.homepage-popover').locator('ion-item').nth(1).click(); - await fillIonInput(home.locator('.text-input-modal').locator('ion-input'), INVITATION_LINK); - await home.locator('.text-input-modal').locator('#next-button').click(); - - await expect(modal).toBeVisible(); - - const title = modal.locator('.modal-header__title'); - const subtitle = modal.locator('.modal-header__text'); - const nextButton = modal.locator('#next-button'); - - await expect(title).toHaveText('Add a new device'); - await expect(nextButton).toHaveText('I understand!'); - - await nextButton.click(); - - const steps = modal.locator('.ms-wizard-stepper__step'); - await expect(title).toHaveText('Get host code'); - await expect(subtitle).toHaveText('Click on the code you see on the main device.'); - await expect(steps).toHaveText(['Host code', 'Guest code', 'Authentication']); - await checkStepper(steps, 0); - await expect(nextButton).toBeHidden(); - - const choices = modal.locator('.button-choice'); - await expect(choices).toHaveText(['5MNO', '6PQR', '7STU', '8VWX']); - await choices.nth(2).click(); - - await checkStepper(steps, 1); - - await home.waitForTimeout(WAIT_TIME); - await checkStepper(steps, 2); - - await expect(title).toHaveText('Authentication'); - await expect(subtitle).toHaveText('Lastly, choose an authentication method for your new device.'); - await expect(nextButton).toBeVisible(); - await expect(nextButton).toBeTrulyDisabled(); - await expect(nextButton).toHaveText('Confirm'); - - const authChoices = modal.locator('.choose-auth-page').locator('ion-radio'); - - await expect(authChoices.nth(0).locator('.item-radio__label')).toHaveText('Use System Authentication'); - await expect(authChoices.nth(0).locator('.item-radio__text:visible')).toHaveText('Unavailable on web'); - await expect(authChoices.nth(0)).toHaveTheClass('radio-disabled'); - - const inputs = modal.locator('.choose-auth-page').locator('.choose-password').locator('ion-input'); - await fillIonInput(inputs.nth(0), 'Password23;-$aze'); - await expect(nextButton).toBeTrulyDisabled(); - await fillIonInput(inputs.nth(1), 'Password23;-$aze'); - await nextButton.scrollIntoViewIfNeeded(); - await expect(nextButton).toBeTrulyEnabled(); - await nextButton.click(); - - await expect(title).toHaveText('Device has been added!'); - await expect(nextButton).toHaveText('Log in'); - await nextButton.click(); - - await expect(modal).toBeHidden(); -}); diff --git a/client/tests/e2e/specs/document_context_menu.spec.ts b/client/tests/e2e/specs/document_context_menu.spec.ts index 180241a8631..62b4fad01c3 100644 --- a/client/tests/e2e/specs/document_context_menu.spec.ts +++ b/client/tests/e2e/specs/document_context_menu.spec.ts @@ -36,12 +36,12 @@ for (const gridMode of [false, true]) { msTest(`Document actions default state in ${gridMode ? 'grid' : 'list'} mode`, async ({ documents }) => { await expect(documents.locator('.file-context-menu')).toBeHidden(); if (!gridMode) { - const entry = documents.locator('.folder-container').locator('.file-list-item').nth(2); + const entry = documents.locator('.folder-container').locator('.file-list-item').nth(0); await entry.hover(); await entry.locator('.options-button').click(); } else { await toggleViewMode(documents); - const entry = documents.locator('.folder-container').locator('.file-card-item').nth(2); + const entry = documents.locator('.folder-container').locator('.file-card-item').nth(0); await entry.hover(); await entry.locator('.card-option').click(); } @@ -66,11 +66,11 @@ for (const gridMode of [false, true]) { msTest(`Document popover on right click in ${gridMode ? 'grid' : 'list'} mode`, async ({ documents }) => { await expect(documents.locator('.file-context-menu')).toBeHidden(); if (!gridMode) { - const entry = documents.locator('.folder-container').locator('.file-list-item').nth(2); + const entry = documents.locator('.folder-container').locator('.file-list-item').nth(0); await entry.click({ button: 'right' }); } else { await toggleViewMode(documents); - const entry = documents.locator('.folder-container').locator('.file-card-item').nth(2); + const entry = documents.locator('.folder-container').locator('.file-card-item').nth(0); await entry.click({ button: 'right' }); } await expect(documents.locator('.file-context-menu')).toBeVisible(); @@ -107,7 +107,7 @@ for (const gridMode of [false, true]) { await entry.locator('ion-checkbox').click(); await expect(entry.locator('ion-checkbox')).toHaveState('checked'); } - await entries.nth(2).click({ button: 'right' }); + await entries.nth(0).click({ button: 'right' }); await expect(documents.locator('.file-context-menu')).toBeVisible(); const popover = documents.locator('.file-context-menu'); @@ -155,10 +155,10 @@ for (const gridMode of [false, true]) { await clickAction(await openPopover(documents), 'Rename'); await fillInputModal(documents, 'My file', true); if (!gridMode) { - const entry = documents.locator('.folder-container').locator('.file-list-item').nth(2); + const entry = documents.locator('.folder-container').locator('.file-list-item').nth(0); await expect(entry.locator('.file-name').locator('.file-name__label')).toHaveText('My file'); } else { - const entry = documents.locator('.folder-container').locator('.file-card-item').nth(2); + const entry = documents.locator('.folder-container').locator('.file-card-item').nth(0); await expect(entry.locator('.file-card__title')).toHaveText('My file'); } }); @@ -169,7 +169,7 @@ for (const gridMode of [false, true]) { } let fileName; if (gridMode) { - fileName = await documents.locator('.folder-container').locator('.file-card-item').nth(2).locator('.file-card__title').textContent(); + fileName = await documents.locator('.folder-container').locator('.file-card-item').nth(0).locator('.file-card__title').textContent(); } else { fileName = await documents .locator('.folder-container') @@ -193,12 +193,12 @@ for (const gridMode of [false, true]) { msTest(`Document actions default state in a read only workspace in ${gridMode ? 'grid' : 'list'} mode`, async ({ documentsReadOnly }) => { await expect(documentsReadOnly.locator('.file-context-menu')).toBeHidden(); if (!gridMode) { - const entry = documentsReadOnly.locator('.folder-container').locator('.file-list-item').nth(2); + const entry = documentsReadOnly.locator('.folder-container').locator('.file-list-item').nth(0); await entry.hover(); await entry.locator('.options-button').click(); } else { await toggleViewMode(documentsReadOnly); - const entry = documentsReadOnly.locator('.folder-container').locator('.file-card-item').nth(2); + const entry = documentsReadOnly.locator('.folder-container').locator('.file-card-item').nth(0); await entry.hover(); await entry.locator('.card-option').click(); } diff --git a/client/tests/e2e/specs/home_page.spec.ts b/client/tests/e2e/specs/home_page.spec.ts index 19e1dfad299..f8d41632932 100644 --- a/client/tests/e2e/specs/home_page.spec.ts +++ b/client/tests/e2e/specs/home_page.spec.ts @@ -116,7 +116,7 @@ msTest('Login', async ({ home }) => { await expect(home).toBeWorkspacePage(); await expect(home).toHaveHeader(['My workspaces'], false, false); const profile = home.locator('.topbar').locator('.profile-header'); - await expect(profile.locator('.text-content-name')).toHaveText('Gordon Freeman'); + await expect(profile.locator('.text-content-name')).toHaveText('Alicey McAliceFace'); }); msTest('Login page and back to device list', async ({ home }) => { @@ -143,7 +143,7 @@ msTest('Login with invalid password', async ({ home }) => { await expect(home).toBeHomePage(); }); -msTest('Logout and go back to devices list', async ({ home }) => { +msTest.fail('Logout and go back to devices list', async ({ home }) => { await home.locator('.organization-list').locator('.organization-card').nth(0).click(); await fillIonInput(home.locator('#password-input').locator('ion-input'), 'P@ssw0rd.'); await home.locator('.login-card-footer').locator('.login-button').click(); diff --git a/client/tests/e2e/specs/invitations_popover.spec.ts b/client/tests/e2e/specs/invitations_popover.spec.ts index 5acda82a586..a3d2931b429 100644 --- a/client/tests/e2e/specs/invitations_popover.spec.ts +++ b/client/tests/e2e/specs/invitations_popover.spec.ts @@ -3,19 +3,19 @@ import { answerQuestion, expect, fillInputModal, getClipboardText, msTest, setWriteClipboardPermission } from '@tests/e2e/helpers'; msTest('Profile popover default state', async ({ connected }) => { - await expect(connected.locator('.topbar').locator('#invitations-button')).toHaveText('2 invitations'); + await expect(connected.locator('.topbar').locator('#invitations-button')).toHaveText('One invitation'); await expect(connected.locator('.invitations-list-popover')).toBeHidden(); await connected.locator('.topbar').locator('#invitations-button').click(); const popover = connected.locator('.invitations-list-popover'); await expect(popover).toBeVisible(); await expect(popover.locator('.invitations-list-header__title')).toHaveText('Invitations'); - await expect(popover.locator('.invitations-list-header__counter')).toHaveText('2'); + await expect(popover.locator('.invitations-list-header__counter')).toHaveText('1'); await expect(popover.locator('.invitations-list-header__button')).toHaveText('Invite a new member'); const invitations = popover.locator('.invitation-list-item'); - await expect(invitations).toHaveCount(2); - await expect(invitations.locator('.invitation-email')).toHaveText(['shadowheart@swordcoast.faerun', 'gale@waterdeep.faerun']); - await expect(invitations.locator('.invitation-actions-date')).toHaveText(['now', 'now'], { useInnerText: true }); + await expect(invitations).toHaveCount(1); + await expect(invitations.locator('.invitation-email')).toHaveText('zack@example.invalid'); + await expect(invitations.locator('.invitation-actions-date')).toHaveText('Jan 7, 2000', { useInnerText: true }); const firstInv = invitations.nth(0); await expect(firstInv.locator('.copy-link')).toBeHidden(); await firstInv.hover(); @@ -46,7 +46,7 @@ msTest('Cancel invitation cancel', async ({ connected }) => { await answerQuestion(connected, false, { expectedTitleText: 'Cancel invitation', expectedQuestionText: - 'The invitation sent to shadowheart@swordcoast.faerun and the invitation link \ + 'The invitation sent to zack@example.invalid and the invitation link \ will no longer be valid. Are you sure you want to continue?', expectedPositiveText: 'Cancel invitation', expectedNegativeText: 'Keep invitation', @@ -72,9 +72,21 @@ msTest('Invite new user', async ({ connected }) => { await fillInputModal(connected, 'zana@wraeclast'); // cspell:disable-next-line await expect(connected).toShowToast('An invitation to join the organization has been sent to zana@wraeclast.', 'Success'); + await expect(connected.locator('.topbar').locator('#invitations-button')).toHaveText('2 invitations'); + + await expect(connected.locator('.invitations-list-popover')).toBeHidden(); + await connected.locator('.topbar').locator('#invitations-button').click(); + await expect(popover).toBeVisible(); + await expect(popover.locator('.invitations-list-header__title')).toHaveText('Invitations'); + await expect(popover.locator('.invitations-list-header__counter')).toHaveText('2'); + const invitations = popover.locator('.invitation-list-item'); + await expect(invitations).toHaveCount(2); + // cspell:disable-next-line + await expect(invitations.locator('.invitation-email')).toHaveText(['zack@example.invalid', 'zana@wraeclast']); + await expect(invitations.locator('.invitation-actions-date')).toHaveText(['Jan 7, 2000', 'now'], { useInnerText: true }); }); -msTest('Invite user with already existing email', async ({ connected }) => { +msTest.fail('Invite user with already existing email', async ({ connected }) => { await connected.locator('.topbar').locator('#invitations-button').click(); const popover = connected.locator('.invitations-list-popover'); await popover.locator('.invitations-list-header__button').click(); diff --git a/client/tests/e2e/specs/my_profile_page.spec.ts b/client/tests/e2e/specs/my_profile_page.spec.ts index 5011615f24d..1037132ab5a 100644 --- a/client/tests/e2e/specs/my_profile_page.spec.ts +++ b/client/tests/e2e/specs/my_profile_page.spec.ts @@ -2,7 +2,7 @@ import { expect, fillIonInput, msTest } from '@tests/e2e/helpers'; -msTest('Check devices list', async ({ myProfilePage }) => { +msTest.fail('Check devices list', async ({ myProfilePage }) => { await expect(myProfilePage.locator('.menu-list__item').nth(1)).toHaveText('My devices'); await myProfilePage.locator('.menu-list__item').nth(1).click(); await expect(myProfilePage.locator('#add-device-button')).toHaveText('Add a new device'); diff --git a/client/tests/e2e/specs/organization_information.spec.ts b/client/tests/e2e/specs/organization_information.spec.ts index 699c55cf82b..28e5b9a0fb0 100644 --- a/client/tests/e2e/specs/organization_information.spec.ts +++ b/client/tests/e2e/specs/organization_information.spec.ts @@ -2,7 +2,7 @@ import { expect, msTest } from '@tests/e2e/helpers'; -msTest('User list default state', async ({ organizationPage }) => { +msTest('Org info default state', async ({ organizationPage }) => { const container = organizationPage.locator('.org-info-container'); const configContainer = container.locator('.org-config'); const usersContainer = container.locator('.org-user'); @@ -15,13 +15,13 @@ msTest('User list default state', async ({ organizationPage }) => { await expect(configContainer.locator('.org-config-list-item').nth(0).locator('.org-config-list-item__value')).toHaveText(['Enabled']); await expect(configContainer.locator('.org-config-list-item').nth(1).locator('.org-config-list-item__value')).toHaveText(['Unlimited']); await expect(configContainer.locator('.org-config-list-item').nth(2).locator('.server-address-value__text')).toHaveText( - 'parsec3://example.com/MyOrg', + /^parsec3:\/\/.+$/, ); await expect(usersContainer.locator('.user-active-header').locator('.user-active-header__title')).toHaveText('Active'); - await expect(usersContainer.locator('.user-active-header').locator('.title-h4')).toHaveText('5'); + await expect(usersContainer.locator('.user-active-header').locator('.title-h4')).toHaveText('0'); await expect(usersContainer.locator('.user-active-list').locator('.label-profile')).toHaveText(['Administrator', 'Member', 'External']); await expect(usersContainer.locator('.user-active-list').locator('.user-active-list-item__value')).toHaveText(['2', '2', '1']); await expect(usersContainer.locator('.user-revoked-header').locator('.user-revoked-header__title')).toHaveText('Revoked'); - await expect(usersContainer.locator('.user-revoked-header').locator('.title-h4')).toHaveText('3'); + await expect(usersContainer.locator('.user-revoked-header').locator('.title-h4')).toHaveText('0'); }); diff --git a/client/tests/e2e/specs/organization_switch_popover.spec.ts b/client/tests/e2e/specs/organization_switch_popover.spec.ts index 54029c1129a..7970f5ea85b 100644 --- a/client/tests/e2e/specs/organization_switch_popover.spec.ts +++ b/client/tests/e2e/specs/organization_switch_popover.spec.ts @@ -6,7 +6,7 @@ msTest('Open organization switch popover', async ({ connected }) => { const popoverButton = connected.locator('.sidebar').locator('.sidebar-header').locator('.organization-card-header-desktop'); const popover = connected.locator('.popover-switch'); - await expect(popoverButton.locator('.organization-text')).toHaveText('MyOrg'); + await expect(popoverButton.locator('.organization-text')).toHaveText(/^Org\d+$/); await expect(popover).toBeHidden(); await popoverButton.click(); await expect(popover).toBeVisible(); diff --git a/client/tests/e2e/specs/profile_popover.spec.ts b/client/tests/e2e/specs/profile_popover.spec.ts index 5ada1a1f26d..9a960d72b4f 100644 --- a/client/tests/e2e/specs/profile_popover.spec.ts +++ b/client/tests/e2e/specs/profile_popover.spec.ts @@ -4,11 +4,12 @@ import { expect, msTest } from '@tests/e2e/helpers'; msTest('Profile popover default state', async ({ connected }) => { await expect(connected.locator('.profile-header-popover')).toBeHidden(); + await expect(connected.locator('.topbar').locator('.profile-header').locator('.text-content-name')).toHaveText('Alicey McAliceFace'); await connected.locator('.topbar').locator('.profile-header').click(); await expect(connected.locator('.profile-header-popover')).toBeVisible(); const popover = connected.locator('.profile-header-popover'); const header = popover.locator('.header-list'); - await expect(header.locator('.header-list-email')).toHaveText('user@host.com'); + await expect(header.locator('.header-list-email')).toHaveText('alice@example.com'); await expect(header.locator('.profile')).toHaveText('Administrator'); const buttons = popover.locator('.main-list').getByRole('listitem'); diff --git a/client/tests/e2e/specs/sidebar.spec.ts b/client/tests/e2e/specs/sidebar.spec.ts index 3de124542eb..cbe885050a7 100644 --- a/client/tests/e2e/specs/sidebar.spec.ts +++ b/client/tests/e2e/specs/sidebar.spec.ts @@ -22,8 +22,11 @@ msTest('Sidebar in organization management', async ({ organizationPage }) => { await expect(items).toHaveText(['Users', 'Information']); }); -msTest('Sidebar in workspaces page', async ({ connected }) => { - const sidebar = connected.locator('.sidebar'); +msTest('Sidebar in workspaces page', async ({ workspaces }) => { + const sidebar = workspaces.locator('.sidebar'); + + await workspaces.locator('.workspaces-container-grid').locator('.workspace-card-item').nth(1).click(); + await workspaces.locator('#connected-header').locator('.topbar-left').locator('ion-breadcrumb').nth(0).click(); await expect(sidebar.locator('.back-button')).toBeHidden(); @@ -32,7 +35,7 @@ msTest('Sidebar in workspaces page', async ({ connected }) => { await expect(mainButtons.nth(0)).not.toHaveTheClass('active'); await expect(mainButtons.nth(1)).toHaveTheClass('active'); - await expect(sidebar.locator('.file-workspaces')).toBeVisible(); + await expect(sidebar.locator('.file-workspaces')).toBeHidden(); await expect(sidebar.locator('.favorites')).toBeHidden(); await expect(sidebar.locator('.workspaces')).toBeVisible(); await expect(sidebar.locator('.workspaces').locator('.list-sidebar-header')).toHaveText('Recent workspaces'); diff --git a/client/tests/e2e/specs/user_greet.spec.ts b/client/tests/e2e/specs/user_greet.spec.ts index e9db2360882..94d62b0c0e2 100644 --- a/client/tests/e2e/specs/user_greet.spec.ts +++ b/client/tests/e2e/specs/user_greet.spec.ts @@ -1,115 +1,323 @@ // Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS -import { answerQuestion, expect, msTest } from '@tests/e2e/helpers'; +import { Locator, Page } from '@playwright/test'; +import { + answerQuestion, + expect, + fillInputModal, + fillIonInput, + getClipboardText, + msTest, + setWriteClipboardPermission, +} from '@tests/e2e/helpers'; -msTest('Open the greet user modal', async ({ userGreetModal }) => { - await expect(userGreetModal.locator('.modal-header__title')).toHaveText('Onboard a new user'); - await expect(userGreetModal.locator('#next-button')).toHaveText('Start'); - await expect(userGreetModal.locator('.closeBtn')).toBeVisible(); -}); +interface ModalData { + modal: Locator; + nextButton: Locator; + title: Locator; + subtitle: Locator; + content: Locator; + closeButton: Locator; +} + +async function initModals(hostPage: Page, guestPage: Page): Promise<[ModalData, ModalData]> { + // Invite a new user and retrieve the invitation link + await hostPage.locator('#activate-users-ms-action-bar').locator('#button-invite-user').click(); + // cspell:disable-next-line + await fillInputModal(hostPage, 'gordon.freeman@blackmesa.nm'); + // cspell:disable-next-line + await expect(hostPage).toShowToast('An invitation to join the organization has been sent to gordon.freeman@blackmesa.nm.', 'Success'); + await hostPage.locator('.topbar').locator('#invitations-button').click(); + const popover = hostPage.locator('.invitations-list-popover'); + await setWriteClipboardPermission(hostPage.context(), true); + const inv = popover.locator('.invitation-list-item').nth(1); + await inv.hover(); + await inv.locator('.copy-link').click(); + await expect(hostPage).toShowToast('Invitation link has been copied to clipboard.', 'Info'); + const invitationLink = await getClipboardText(hostPage); + + // Use the invitation link in the second tab + await guestPage.locator('#create-organization-button').click(); + await expect(guestPage.locator('.homepage-popover')).toBeVisible(); + await guestPage.locator('.homepage-popover').getByRole('listitem').nth(1).click(); + await fillInputModal(guestPage, invitationLink); + const joinModal = guestPage.locator('.join-organization-modal'); + await expect(joinModal).toBeVisible(); + + // Start the greet + await inv.locator('.invitation-actions-buttons').locator('ion-button').nth(1).click(); + + const greetModal = hostPage.locator('.greet-organization-modal'); + + const greetData = { + modal: greetModal, + nextButton: greetModal.locator('#next-button'), + title: greetModal.locator('.modal-header__title'), + subtitle: greetModal.locator('.modal-header__text'), + content: greetModal.locator('.modal-content'), + closeButton: greetModal.locator('.closeBtn'), + }; + await expect(greetData.nextButton).toHaveText('Start'); + await expect(greetData.title).toHaveText('Onboard a new user'); + await greetData.nextButton.click(); + + const joinData = { + modal: joinModal, + nextButton: joinModal.locator('#next-button'), + title: joinModal.locator('.modal-header__title'), + subtitle: joinModal.locator('.modal-header__text'), + content: joinModal.locator('.modal-content'), + closeButton: joinModal.locator('.closeBtn'), + }; + + // Start the join + await expect(joinData.nextButton).toHaveText('I understand!'); + await joinData.nextButton.click(); + + return [greetData, joinData]; +} + +msTest('Greet user whole process', async ({ usersPage, secondTab }) => { + // Very slow test since it syncs the greet and join + msTest.setTimeout(120_000); + + const [greetData, joinData] = await initModals(usersPage, secondTab); + + // Check the provide code page from the host and retrieve the code + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details'], 0); + await expect(greetData.title).toHaveText('Share your code'); + await expect(greetData.subtitle).toHaveText('Give the code below to the guest.'); + const greetCode = (await greetData.content.locator('.host-code').locator('.code').textContent()) ?? ''; + expect(greetCode).toMatch(/^[A-Z0-9]{4}$/); + + // Check the enter code page from the guest and select the code + await expect(joinData.title).toHaveText('Get host code'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details', 'Authentication'], 0); + await expect(joinData.content.locator('.button-choice')).toHaveCount(4); + await joinData.content.locator('.button-choice', { hasText: greetCode }).click(); + + // Check the provide code page from the guest and retrieve the code + await expect(joinData.title).toHaveText('Share your code'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details', 'Authentication'], 1); + const joinCode = (await joinData.content.locator('.guest-code').locator('.code').textContent()) ?? ''; + expect(joinCode).toMatch(/^[A-Z0-9]{4}$/); + + // Check the enter code page from the host and select the code + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details'], 1); + await expect(greetData.title).toHaveText('Get guest code'); + await expect(greetData.subtitle).toHaveText('Click on the code given to you by the guest.'); + await expect(greetData.content.locator('.button-choice')).toHaveCount(4); + await greetData.content.locator('.button-choice', { hasText: joinCode }).click(); + + // Host waits for guest to fill out the information + await expect(greetData.title).toHaveText('Contact details'); + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details'], 2); + await expect(greetData.nextButton).toBeHidden(); + + // Fill out the joiner information + await expect(joinData.title).toHaveText('Your contact details'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details', 'Authentication'], 2); + await expect(joinData.nextButton).toHaveDisabledAttribute(); + await fillIonInput(joinData.content.locator('#get-user-info').locator('ion-input').nth(0), 'Gordon Freeman'); + await expect(joinData.content.locator('#get-user-info').locator('ion-input').nth(1).locator('input')).toHaveValue( + 'gordon.freeman@blackmesa.nm', + ); + await joinData.nextButton.click(); + await expect(joinData.nextButton).toBeHidden(); + await expect(joinData.modal.locator('.spinner-container')).toBeVisible(); + await expect(joinData.modal.locator('.spinner-container')).toHaveText('(Waiting for the host)'); -msTest('Go through the greet process', async ({ userGreetModal }) => { - const title = userGreetModal.locator('.modal-header__title'); - const subtitle = userGreetModal.locator('.modal-header__text'); - const nextButton = userGreetModal.locator('#next-button'); - const modalContent = userGreetModal.locator('.modal-content'); - - await nextButton.click(); - - await expect(userGreetModal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details'], 0); - - await expect(title).toHaveText('Share your code'); - await expect(subtitle).toHaveText('Give the code below to the guest.'); - await expect(modalContent.locator('.code:visible')).toHaveText('2EDF'); - await expect(nextButton).toBeHidden(); - await userGreetModal.page().waitForTimeout(200); - - await expect(userGreetModal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details'], 1); - await expect(title).toHaveText('Get guest code'); - await expect(subtitle).toHaveText('Click on the code given to you by the guest.'); - const choices = modalContent.locator('.code:visible'); - await expect(choices).toHaveText(['1ABC', '2DEF', '3GHI', '4JKL']); - await expect(nextButton).toBeHidden(); - await choices.nth(1).click(); - - await expect(title).toHaveText('Contact details'); - await expect(userGreetModal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details'], 2); - await expect(nextButton).toBeHidden(); - await userGreetModal.page().waitForTimeout(200); - - await expect(title).toHaveText('Contact details'); - await expect(subtitle).toHaveText('You can update the user name, device and profile.'); - await expect(userGreetModal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details'], 2); - await expect(nextButton).toBeVisible(); - await expect(nextButton).toHaveDisabledAttribute(); - - await expect(modalContent.locator('.user-info-page').locator('ion-input').nth(0).locator('input')).toHaveValue('Gordon Freeman'); - await expect(modalContent.locator('.user-info-page').locator('ion-input').nth(1)).toHaveTheClass('input-disabled'); - await expect(modalContent.locator('.user-info-page').locator('ion-input').nth(1).locator('input')).toHaveValue( + // host reviews the information and chose profile + await expect(greetData.title).toHaveText('Contact details'); + await expect(greetData.subtitle).toHaveText('You can update the user name, device and profile.'); + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details'], 2); + await expect(greetData.nextButton).toBeVisible(); + await expect(greetData.nextButton).toHaveDisabledAttribute(); + await expect(greetData.content.locator('.user-info-page').locator('ion-input').nth(0).locator('input')).toHaveValue('Gordon Freeman'); + await expect(greetData.content.locator('.user-info-page').locator('ion-input').nth(1)).toHaveTheClass('input-disabled'); + await expect(greetData.content.locator('.user-info-page').locator('ion-input').nth(1).locator('input')).toHaveValue( 'gordon.freeman@blackmesa.nm', ); - const profileButton = modalContent.locator('.user-info-page').locator('.filter-button'); + const profileButton = greetData.content.locator('.user-info-page').locator('.filter-button'); await expect(profileButton).toHaveText('Choose a profile'); await profileButton.click(); - const profileDropdown = userGreetModal.page().locator('.dropdown-popover'); + const profileDropdown = usersPage.locator('.dropdown-popover'); await expect(profileDropdown.getByRole('listitem').locator('.option-text__label')).toHaveText(['Administrator', 'Member', 'External']); await profileDropdown.getByRole('listitem').nth(1).click(); await expect(profileButton).toHaveText('Member'); - await expect(nextButton).toNotHaveDisabledAttribute(); - await expect(nextButton).toHaveText('Approve'); - await nextButton.click(); - - await expect(title).toHaveText('User has been added successfully!'); - await expect(nextButton).toNotHaveDisabledAttribute(); - await expect(nextButton).toBeVisible(); - await expect(modalContent.locator('.final-step').locator('.person-name')).toHaveText('Gordon Freeman'); - await expect(modalContent.locator('.final-step').locator('.user-info__email').locator('.cell')).toHaveText('gordon.freeman@blackmesa.nm'); - await expect(modalContent.locator('.final-step').locator('.user-info__role').locator('.label-profile')).toHaveText('Member'); - await nextButton.click(); - - await expect(userGreetModal.page().locator('.greet-organization-modal')).toBeHidden(); - await expect(userGreetModal.page()).toShowToast('Gordon Freeman can now access to the organization.', 'Success'); + await expect(greetData.nextButton).toNotHaveDisabledAttribute(); + await expect(greetData.nextButton).toHaveText('Approve'); + await greetData.nextButton.click(); + + // Joiner chose auth + await expect(joinData.title).toHaveText('Authentication'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details', 'Authentication'], 3); + await expect(joinData.nextButton).toHaveText('Join the organization'); + await expect(joinData.nextButton).toHaveDisabledAttribute(); + + // host is done + await expect(greetData.title).toHaveText('User has been added successfully!'); + await expect(greetData.nextButton).not.toHaveDisabledAttribute(); + await expect(greetData.nextButton).toBeVisible(); + await expect(greetData.content.locator('.final-step').locator('.person-name')).toHaveText('Gordon Freeman'); + await expect(greetData.content.locator('.final-step').locator('.user-info__email').locator('.cell')).toHaveText( + 'gordon.freeman@blackmesa.nm', + ); + await expect(greetData.content.locator('.final-step').locator('.user-info__role').locator('.label-profile')).toHaveText('Member'); + await greetData.nextButton.click(); + await expect(greetData.modal).toBeHidden(); + await expect(usersPage).toShowToast('Gordon Freeman can now access to the organization.', 'Success'); + // Also check that the user list gets updated with the new user + + // Joiner sets password + const authRadio = joinData.content.locator('.choose-auth-page').locator('.radio-list-item'); + await expect(authRadio).toHaveCount(2); + await expect(authRadio.nth(0)).toHaveTheClass('radio-disabled'); + await expect(authRadio.nth(0).locator('.item-radio__label')).toHaveText('Use System Authentication'); + await expect(authRadio.nth(0).locator('.item-radio__text:visible')).toHaveText('Unavailable on web'); + await expect(authRadio.nth(1)).toHaveText('Use Password'); + const passwordChoice = joinData.content.locator('#get-password').locator('.choose-password'); + await passwordChoice.scrollIntoViewIfNeeded(); + await fillIonInput(passwordChoice.locator('ion-input').nth(0), 'AVeryL0ngP@ssw0rd'); + await expect(joinData.nextButton).toHaveDisabledAttribute(); + await fillIonInput(passwordChoice.locator('ion-input').nth(1), 'AVeryL0ngP@ssw0rd'); + await joinData.nextButton.scrollIntoViewIfNeeded(); + await expect(joinData.nextButton).not.toHaveDisabledAttribute(); + await joinData.nextButton.click(); + await expect(joinData.title).toHaveText(/^You have joined the organization Org\d+!$/); + await expect(joinData.nextButton).not.toHaveDisabledAttribute(); + await joinData.nextButton.click(); + await expect(joinData.modal).toBeHidden(); + await expect(secondTab).toShowToast('You successfully joined the organization.', 'Success'); + // Automatically logged in + await expect(secondTab.locator('#connected-header')).toContainText('My workspaces'); + await expect(secondTab).toBeWorkspacePage(); + const profile = secondTab.locator('.topbar').locator('.profile-header'); + await expect(profile.locator('.text-content-name')).toHaveText('Gordon Freeman'); }); -msTest('User greet select invalid SAS code', async ({ userGreetModal }) => { - const title = userGreetModal.locator('.modal-header__title'); - const nextButton = userGreetModal.locator('#next-button'); - await nextButton.click(); +msTest('Host selects invalid SAS code', async ({ usersPage, secondTab }) => { + // Very slow test since it syncs the greet and join + msTest.setTimeout(120_000); + + const [greetData, joinData] = await initModals(usersPage, secondTab); + // Check the provide code page from the host and retrieve the code + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details'], 0); + await expect(greetData.title).toHaveText('Share your code'); + await expect(greetData.subtitle).toHaveText('Give the code below to the guest.'); + const greetCode = (await greetData.content.locator('.host-code').locator('.code').textContent()) ?? ''; + expect(greetCode).toMatch(/^[A-Z0-9]{4}$/); + + // Check the enter code page from the guest and select the code + await expect(joinData.title).toHaveText('Get host code'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details', 'Authentication'], 0); + await expect(joinData.content.locator('.button-choice')).toHaveCount(4); + await joinData.content.locator('.button-choice', { hasText: greetCode }).click(); + + // Check the provide code page from the guest and retrieve the code + await expect(joinData.title).toHaveText('Share your code'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details', 'Authentication'], 1); + const joinCode = (await joinData.content.locator('.guest-code').locator('.code').textContent()) ?? ''; + expect(joinCode).toMatch(/^[A-Z0-9]{4}$/); - await expect(title).toHaveText('Get guest code'); - const choices = userGreetModal.locator('.modal-content').locator('.code:visible'); - await choices.nth(0).click(); + // Check the enter code page from the host and select the code + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details'], 1); + await expect(greetData.title).toHaveText('Get guest code'); + await expect(greetData.subtitle).toHaveText('Click on the code given to you by the guest.'); + await expect(greetData.content.locator('.button-choice')).toHaveCount(4); + await greetData.modal.locator('.button-choice').filter({ hasNotText: joinCode }).nth(0).click(); - await expect(userGreetModal.page()).toShowToast('You did not select the correct code. Please restart the onboarding process.', 'Error'); - await expect(title).toHaveText('Onboard a new user'); + await expect(usersPage).toShowToast('You did not select the correct code. Please restart the onboarding process.', 'Error'); + await expect(secondTab).toShowToast('The host has selected the wrong code.', 'Error'); + + // Back to the beginning + await expect(greetData.nextButton).toHaveText('Start'); + await expect(greetData.title).toHaveText('Onboard a new user'); + + // Back to the beginning + await expect(joinData.title).toHaveText('Welcome to Parsec!'); + await expect(joinData.nextButton).toHaveText('I understand!'); }); -msTest('User greet select no SAS code', async ({ userGreetModal }) => { - const title = userGreetModal.locator('.modal-header__title'); - const nextButton = userGreetModal.locator('#next-button'); - await nextButton.click(); +msTest('Host selects no SAS code', async ({ usersPage, secondTab }) => { + // Very slow test since it syncs the greet and join + msTest.setTimeout(120_000); + + const [greetData, joinData] = await initModals(usersPage, secondTab); + // Check the provide code page from the host and retrieve the code + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details'], 0); + await expect(greetData.title).toHaveText('Share your code'); + await expect(greetData.subtitle).toHaveText('Give the code below to the guest.'); + const greetCode = (await greetData.content.locator('.host-code').locator('.code').textContent()) ?? ''; + expect(greetCode).toMatch(/^[A-Z0-9]{4}$/); + + // Check the enter code page from the guest and select the code + await expect(joinData.title).toHaveText('Get host code'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details', 'Authentication'], 0); + await expect(joinData.content.locator('.button-choice')).toHaveCount(4); + await joinData.content.locator('.button-choice', { hasText: greetCode }).click(); + + // Check the provide code page from the guest and retrieve the code + await expect(joinData.title).toHaveText('Share your code'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details', 'Authentication'], 1); + const joinCode = (await joinData.content.locator('.guest-code').locator('.code').textContent()) ?? ''; + expect(joinCode).toMatch(/^[A-Z0-9]{4}$/); - await expect(title).toHaveText('Get guest code'); - await userGreetModal.locator('.modal-content').locator('.button-none').click(); + // Check the enter code page from the host and select the code + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details'], 1); + await expect(greetData.title).toHaveText('Get guest code'); + await expect(greetData.subtitle).toHaveText('Click on the code given to you by the guest.'); + await expect(greetData.content.locator('.button-none')).toHaveText('None shown'); + await greetData.content.locator('.button-none').click(); - await expect(userGreetModal.page()).toShowToast( + await expect(usersPage).toShowToast( 'If you did not see the correct code, this could be a sign of a security issue during the onboarding. Please restart the process.', 'Error', ); - await expect(title).toHaveText('Onboard a new user'); + await expect(secondTab).toShowToast('The host has cancelled the process.', 'Error'); + + // Back to the beginning + await expect(greetData.nextButton).toHaveText('Start'); + await expect(greetData.title).toHaveText('Onboard a new user'); + + // Back to the beginning + await expect(joinData.title).toHaveText('Welcome to Parsec!'); + await expect(joinData.nextButton).toHaveText('I understand!'); }); -msTest('Close user greet process', async ({ userGreetModal }) => { - const title = userGreetModal.locator('.modal-header__title'); - const nextButton = userGreetModal.locator('#next-button'); - const closeButton = userGreetModal.locator('.closeBtn'); - const modalContent = userGreetModal.locator('.modal-content'); +msTest('Host closes greet process', async ({ usersPage, secondTab }) => { + // Very slow test since it syncs the greet and join + msTest.setTimeout(120_000); + + const [greetData, joinData] = await initModals(usersPage, secondTab); + + // Check the provide code page from the host and retrieve the code + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details'], 0); + await expect(greetData.title).toHaveText('Share your code'); + await expect(greetData.subtitle).toHaveText('Give the code below to the guest.'); + const greetCode = (await greetData.content.locator('.host-code').locator('.code').textContent()) ?? ''; + expect(greetCode).toMatch(/^[A-Z0-9]{4}$/); - await nextButton.click(); - await expect(title).toHaveText('Get guest code'); + // Check the enter code page from the guest and select the code + await expect(joinData.title).toHaveText('Get host code'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details', 'Authentication'], 0); + await expect(joinData.content.locator('.button-choice')).toHaveCount(4); + await joinData.content.locator('.button-choice', { hasText: greetCode }).click(); - await closeButton.click(); - await answerQuestion(userGreetModal.page(), false, { + // Check the provide code page from the guest and retrieve the code + await expect(joinData.title).toHaveText('Share your code'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details', 'Authentication'], 1); + const joinCode = (await joinData.content.locator('.guest-code').locator('.code').textContent()) ?? ''; + expect(joinCode).toMatch(/^[A-Z0-9]{4}$/); + + // Check the enter code page from the host and select the code + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details'], 1); + await expect(greetData.title).toHaveText('Get guest code'); + await expect(greetData.subtitle).toHaveText('Click on the code given to you by the guest.'); + + // Try to close but cancel + await greetData.closeButton.click(); + await answerQuestion(usersPage, false, { expectedTitleText: 'Cancel the onboarding', expectedQuestionText: 'Are you sure you want to cancel the onboarding process? Information will not be saved, you will have to restart.', @@ -117,20 +325,114 @@ msTest('Close user greet process', async ({ userGreetModal }) => { expectedNegativeText: 'Resume', }); - await modalContent.locator('.code:visible').nth(1).click(); - - await closeButton.click(); - await answerQuestion(userGreetModal.page(), false, { + // Now cancel it for real + await greetData.closeButton.click(); + await answerQuestion(usersPage, true, { expectedTitleText: 'Cancel the onboarding', expectedQuestionText: 'Are you sure you want to cancel the onboarding process? Information will not be saved, you will have to restart.', expectedPositiveText: 'Cancel process', expectedNegativeText: 'Resume', }); + await expect(greetData.modal).toBeHidden(); + + // Does not seem to work properly on guest side + // await expect(secondTab).toShowToast('The host has cancelled the process.', 'Error'); + // await expect(joinTitle).toHaveText('Welcome to Parsec!'); + // await expect(joinNextButton).toHaveText('I understand!'); +}); + +msTest('Guest selects invalid SAS code', async ({ usersPage, secondTab }) => { + // Very slow test since it syncs the greet and join + msTest.setTimeout(120_000); + + const [greetData, joinData] = await initModals(usersPage, secondTab); + + // Check the provide code page from the host and retrieve the code + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details'], 0); + await expect(greetData.title).toHaveText('Share your code'); + await expect(greetData.subtitle).toHaveText('Give the code below to the guest.'); + const greetCode = (await greetData.content.locator('.host-code').locator('.code').textContent()) ?? ''; + expect(greetCode).toMatch(/^[A-Z0-9]{4}$/); + + // Check the enter code page from the guest and select the code + await expect(joinData.title).toHaveText('Get host code'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details', 'Authentication'], 0); + await expect(joinData.content.locator('.button-choice')).toHaveCount(4); + await joinData.content.locator('.button-choice').filter({ hasNotText: greetCode }).nth(0).click(); + + await expect(secondTab).toShowToast('You did not select the correct code. Please restart the onboarding process.', 'Error'); + await expect(usersPage).toShowToast('The invitee has selected the wrong code.', 'Error'); + + // Back to the beginning + await expect(greetData.nextButton).toHaveText('Start'); + await expect(greetData.title).toHaveText('Onboard a new user'); + + // Back to the beginning + await expect(joinData.title).toHaveText('Welcome to Parsec!'); + await expect(joinData.nextButton).toHaveText('I understand!'); +}); + +msTest('Guest selects no SAS code', async ({ usersPage, secondTab }) => { + // Very slow test since it syncs the greet and join + msTest.setTimeout(120_000); + + const [greetData, joinData] = await initModals(usersPage, secondTab); + + // Check the provide code page from the host and retrieve the code + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details'], 0); + await expect(greetData.title).toHaveText('Share your code'); + await expect(greetData.subtitle).toHaveText('Give the code below to the guest.'); + const greetCode = (await greetData.content.locator('.host-code').locator('.code').textContent()) ?? ''; + expect(greetCode).toMatch(/^[A-Z0-9]{4}$/); + + // Check the enter code page from the guest and select the code + await expect(joinData.title).toHaveText('Get host code'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details', 'Authentication'], 0); + await expect(joinData.content.locator('.button-none')).toHaveText('None shown'); + await joinData.content.locator('.button-none').click(); + + await expect(secondTab).toShowToast( + 'If you did not see the correct code, this could be a sign of a security issue during the onboarding. Please restart the process.', + 'Error', + ); + await expect(usersPage).toShowToast('The invitee has cancelled the process.', 'Error'); + + // Back to the beginning + await expect(greetData.nextButton).toHaveText('Start'); + await expect(greetData.title).toHaveText('Onboard a new user'); + + // Back to the beginning + await expect(joinData.title).toHaveText('Welcome to Parsec!'); + await expect(joinData.nextButton).toHaveText('I understand!'); +}); + +msTest('Guest closes greet process', async ({ usersPage, secondTab }) => { + // Very slow test since it syncs the greet and join + msTest.setTimeout(120_000); + + const [greetData, joinData] = await initModals(usersPage, secondTab); + + // Check the provide code page from the host and retrieve the code + await expect(greetData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details'], 0); + await expect(greetData.title).toHaveText('Share your code'); + await expect(greetData.subtitle).toHaveText('Give the code below to the guest.'); + const greetCode = (await greetData.content.locator('.host-code').locator('.code').textContent()) ?? ''; + expect(greetCode).toMatch(/^[A-Z0-9]{4}$/); - await expect(title).toHaveText('Contact details'); - await closeButton.click(); - await answerQuestion(userGreetModal.page(), false, { + // Check the enter code page from the guest and select the code + await expect(joinData.title).toHaveText('Get host code'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details', 'Authentication'], 0); + await expect(joinData.content.locator('.button-choice')).toHaveCount(4); + await joinData.content.locator('.button-choice', { hasText: greetCode }).click(); + + // Check the provide code page from the guest and retrieve the code + await expect(joinData.title).toHaveText('Share your code'); + await expect(joinData.modal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details', 'Authentication'], 1); + + // Try to close but cancel + await joinData.closeButton.click(); + await answerQuestion(secondTab, false, { expectedTitleText: 'Cancel the onboarding', expectedQuestionText: 'Are you sure you want to cancel the onboarding process? Information will not be saved, you will have to restart.', @@ -138,10 +440,19 @@ msTest('Close user greet process', async ({ userGreetModal }) => { expectedNegativeText: 'Resume', }); - await modalContent.locator('.user-info-page').locator('.filter-button').click(); - const profileDropdown = userGreetModal.page().locator('.dropdown-popover'); - await profileDropdown.getByRole('listitem').nth(1).click(); - await nextButton.click(); + // Now cancel it for real + await joinData.closeButton.click(); + await answerQuestion(secondTab, true, { + expectedTitleText: 'Cancel the onboarding', + expectedQuestionText: + 'Are you sure you want to cancel the onboarding process? Information will not be saved, you will have to restart.', + expectedPositiveText: 'Cancel process', + expectedNegativeText: 'Resume', + }); + await expect(joinData.modal).toBeHidden(); - await expect(closeButton).toBeHidden(); + // Does not seem to work properly on host side + // await expect(usersPage).toShowToast('The host has cancelled the process.', 'Error'); + // await expect(greetData.nextButton).toHaveText('Start'); + // await expect(greetData.title).toHaveText('Onboard a new user'); }); diff --git a/client/tests/e2e/specs/user_join.spec.ts b/client/tests/e2e/specs/user_join.spec.ts deleted file mode 100644 index 74e50d7c02f..00000000000 --- a/client/tests/e2e/specs/user_join.spec.ts +++ /dev/null @@ -1,133 +0,0 @@ -// Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS - -import { answerQuestion, expect, fillIonInput, msTest } from '@tests/e2e/helpers'; - -msTest('Opens the user join organization modal', async ({ home }) => { - await expect(home.locator('#create-organization-button')).toHaveText('Create or join'); - await expect(home.locator('.homepage-popover')).toBeHidden(); - await home.locator('#create-organization-button').click(); - await expect(home.locator('.homepage-popover')).toBeVisible(); - await expect(home.locator('.join-organization-modal')).toBeHidden(); - const joinButton = home.locator('.homepage-popover').getByRole('listitem').nth(1); - await expect(joinButton.locator('ion-label')).toHaveText('Join'); - await expect(joinButton.locator('ion-text')).toHaveText('I received an invitation to join an organization'); - await joinButton.click(); - const modal = home.locator('.text-input-modal'); - await expect(modal).toBeVisible(); - await expect(modal.locator('#next-button')).toHaveText('Join'); -}); - -msTest('Go through the join user process', async ({ home, userJoinModal }) => { - const nextButton = userJoinModal.locator('#next-button'); - const title = userJoinModal.locator('.modal-header__title'); - await expect(title).toHaveText('Welcome to Parsec!'); - await expect(nextButton).toHaveText('Continue with '); - await nextButton.click(); - await expect(title).toHaveText('Get host code'); - await expect(userJoinModal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details', 'Authentication'], 0); - const sasCodeButtons = userJoinModal.locator('.button-choice'); - await expect(sasCodeButtons).toHaveCount(4); - await sasCodeButtons.nth(1).click(); - await expect(title).toHaveText('Your contact details'); - await expect(userJoinModal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details', 'Authentication'], 2); - await expect(nextButton).toHaveDisabledAttribute(); - // cspell:disable-next-line - await fillIonInput(userJoinModal.locator('#get-user-info').locator('ion-input').nth(0), 'Shadowheart'); - await expect(userJoinModal.locator('#get-user-info').locator('ion-input').nth(1).locator('input')).toHaveValue( - 'shadowheart@swordcoast.faerun', - ); - await expect(nextButton).toNotHaveDisabledAttribute(); - await nextButton.click(); - await expect(title).toHaveText('Authentication'); - await expect(userJoinModal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details', 'Authentication'], 3); - await expect(nextButton).toHaveText('Join the organization'); - await expect(nextButton).toHaveDisabledAttribute(); - const authRadio = userJoinModal.locator('.choose-auth-page').locator('.radio-list-item'); - await expect(authRadio).toHaveCount(2); - await expect(authRadio.nth(0)).toHaveTheClass('radio-disabled'); - await expect(authRadio.nth(0).locator('.item-radio__label')).toHaveText('Use System Authentication'); - await expect(authRadio.nth(0).locator('.item-radio__text:visible')).toHaveText('Unavailable on web'); - await expect(authRadio.nth(1)).toHaveText('Use Password'); - const passwordChoice = userJoinModal.locator('#get-password').locator('.choose-password'); - await fillIonInput(passwordChoice.locator('ion-input').nth(0), 'AVeryL0ngP@ssw0rd'); - await expect(nextButton).toHaveDisabledAttribute(); - await fillIonInput(passwordChoice.locator('ion-input').nth(1), 'AVeryL0ngP@ssw0rd'); - await nextButton.scrollIntoViewIfNeeded(); - await expect(nextButton).toNotHaveDisabledAttribute(); - await nextButton.click(); - await expect(title).toHaveText('You have joined the organization Test!'); - await expect(nextButton).toNotHaveDisabledAttribute(); - await nextButton.click(); - await expect(userJoinModal).toBeHidden(); - await expect(home).toShowToast('You successfully joined the organization.', 'Success'); -}); - -msTest('User join select invalid SAS code', async ({ userJoinModal }) => { - const nextButton = userJoinModal.locator('#next-button'); - const title = userJoinModal.locator('.modal-header__title'); - await expect(title).toHaveText('Welcome to Parsec!'); - await expect(nextButton).toHaveText('Continue with '); - await nextButton.click(); - await expect(title).toHaveText('Get host code'); - await expect(userJoinModal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details', 'Authentication'], 0); - const sasCodeButtons = userJoinModal.locator('.button-choice'); - await sasCodeButtons.nth(0).click(); - await expect(userJoinModal.page()).toShowToast('You did not select the correct code. Please restart the onboarding process.', 'Error'); - await expect(title).toHaveText('Welcome to Parsec!'); - await expect(nextButton).toHaveText('Continue with '); -}); - -msTest('User join select no SAS code', async ({ userJoinModal }) => { - const nextButton = userJoinModal.locator('#next-button'); - const title = userJoinModal.locator('.modal-header__title'); - await expect(title).toHaveText('Welcome to Parsec!'); - await expect(nextButton).toHaveText('Continue with '); - await nextButton.click(); - await expect(title).toHaveText('Get host code'); - await expect(userJoinModal).toHaveWizardStepper(['Host code', 'Guest code', 'Contact details', 'Authentication'], 0); - const sasCodeNone = userJoinModal.locator('.button-none'); - await sasCodeNone.click(); - await expect(userJoinModal.page()).toShowToast( - 'If you did not see the correct code, this could be a sign of a security issue during the onboarding. Please restart the process.', - 'Error', - ); - await expect(title).toHaveText('Welcome to Parsec!'); - await expect(nextButton).toHaveText('Continue with '); -}); - -msTest('Close user join process', async ({ userJoinModal }) => { - const closeButton = userJoinModal.locator('.closeBtn'); - await expect(closeButton).toBeVisible(); - - await closeButton.click(); - await answerQuestion(userJoinModal.page(), false, { - expectedTitleText: 'Cancel the onboarding', - expectedQuestionText: - 'Are you sure you want to cancel the onboarding process? Information will not be saved, you will have to restart.', - expectedPositiveText: 'Cancel process', - expectedNegativeText: 'Resume', - }); - - const nextButton = userJoinModal.locator('#next-button'); - await nextButton.click(); - - await closeButton.click(); - await answerQuestion(userJoinModal.page(), false); - - const sasCodeButtons = userJoinModal.locator('.button-choice'); - await sasCodeButtons.nth(1).click(); - - // cspell:disable-next-line - await fillIonInput(userJoinModal.locator('#get-user-info').locator('ion-input').nth(0), 'Shadowheart'); - await nextButton.click(); - - await closeButton.click(); - await answerQuestion(userJoinModal.page(), false); - - const passwordChoice = userJoinModal.locator('#get-password').locator('.choose-password'); - await fillIonInput(passwordChoice.locator('ion-input').nth(0), 'AVeryL0ngP@ssw0rd'); - await fillIonInput(passwordChoice.locator('ion-input').nth(1), 'AVeryL0ngP@ssw0rd'); - await nextButton.click(); - - await expect(closeButton).toBeHidden(); -}); diff --git a/client/tests/e2e/specs/workspaces_actions.spec.ts b/client/tests/e2e/specs/workspaces_actions.spec.ts index d9775252ce9..60b45a3ef02 100644 --- a/client/tests/e2e/specs/workspaces_actions.spec.ts +++ b/client/tests/e2e/specs/workspaces_actions.spec.ts @@ -5,6 +5,11 @@ import { expect, fillInputModal, getClipboardText, msTest } from '@tests/e2e/hel type Mode = 'grid' | 'list' | 'sidebar'; +enum OpenMenuMethod { + Button = 'button', + RightClick = 'rightClick', +} + async function isInGridMode(page: Page): Promise<boolean> { return (await page.locator('#workspaces-ms-action-bar').locator('#grid-view').getAttribute('disabled')) !== null; } @@ -17,20 +22,35 @@ async function toggleViewMode(page: Page): Promise<void> { } } -async function openContextMenu(page: Page, mode: Mode): Promise<void> { +async function openContextMenu(page: Page, mode: Mode, method: OpenMenuMethod): Promise<void> { if (mode === 'grid') { const wk = page.locator('.workspaces-container-grid').locator('.workspace-card-item').nth(1); - await wk.locator('.card-option').click(); + if (method === OpenMenuMethod.Button) { + await wk.locator('.card-option').click(); + } else { + await wk.click({ button: 'right' }); + } } else if (mode === 'list') { await toggleViewMode(page); const wk = page.locator('.workspaces-container').locator('.workspace-list-item').nth(1); - await wk.locator('.workspace-options').click(); + if (method === OpenMenuMethod.Button) { + await wk.locator('.workspace-options').click(); + } else { + await wk.click({ button: 'right' }); + } } else { + // Sidebar only shows after a workspace has been accessed recently + await page.locator('.workspaces-container-grid').locator('.workspace-card-item').nth(1).click(); + await page.locator('#connected-header').locator('.topbar-left').locator('ion-breadcrumb').nth(0).click(); const sidebar = page.locator('.sidebar'); const a = sidebar.locator('.organization-workspaces').locator('.workspaces'); const wk = a.locator('.list-sidebar-content').locator('.sidebar-item-workspace').nth(0); - await wk.hover(); - await wk.locator('.sidebar-item-workspace__option').click(); + if (method === OpenMenuMethod.Button) { + await wk.hover(); + await wk.locator('.sidebar-item-workspace__option').click(); + } else { + await wk.click({ button: 'right' }); + } } } @@ -50,10 +70,10 @@ const MENU = [ ]; for (const mode of ['grid', 'list', 'sidebar']) { - msTest(`Checks workspace context menu ${mode}`, async ({ connected }) => { - await expect(connected.locator('.workspace-context-menu')).toBeHidden(); - await openContextMenu(connected, mode as Mode); - const contextMenu = connected.locator('.workspace-context-menu'); + msTest(`Checks workspace context menu ${mode}`, async ({ workspaces }) => { + await expect(workspaces.locator('.workspace-context-menu')).toBeHidden(); + await openContextMenu(workspaces, mode as Mode, OpenMenuMethod.Button); + const contextMenu = workspaces.locator('.workspace-context-menu'); await expect(contextMenu).toBeVisible(); await expect(contextMenu.getByRole('group')).toHaveCount(MENU.length); for (const [index, group] of MENU.entries()) { @@ -70,22 +90,11 @@ for (const mode of ['grid', 'list', 'sidebar']) { } }); - msTest(`Checks workspace context menu with right click ${mode}`, async ({ connected }) => { - await expect(connected.locator('.workspace-context-menu')).toBeHidden(); - - if (mode === 'grid') { - const wk = connected.locator('.workspaces-container-grid').locator('.workspace-card-item').nth(1); - await wk.click({ button: 'right' }); - } else if (mode === 'list') { - await toggleViewMode(connected); - const wk = connected.locator('.workspaces-container').locator('.workspace-list-item').nth(1); - await wk.click({ button: 'right' }); - } else { - const wk = connected.locator('.sidebar').locator('.list-sidebar.workspaces').getByRole('listitem').nth(0); - await wk.click({ button: 'right' }); - } + msTest(`Checks workspace context menu with right click ${mode}`, async ({ workspaces }) => { + await expect(workspaces.locator('.workspace-context-menu')).toBeHidden(); + await openContextMenu(workspaces, mode as Mode, OpenMenuMethod.RightClick); - const contextMenu = connected.locator('.workspace-context-menu'); + const contextMenu = workspaces.locator('.workspace-context-menu'); await expect(contextMenu).toBeVisible(); await expect(contextMenu.getByRole('group')).toHaveCount(MENU.length); for (const [index, group] of MENU.entries()) { @@ -102,61 +111,63 @@ for (const mode of ['grid', 'list', 'sidebar']) { } }); - msTest(`Navigate into a workspace ${mode}`, async ({ connected }) => { + msTest(`Navigate into a workspace ${mode}`, async ({ workspaces }) => { if (mode === 'grid') { - await connected.locator('.workspaces-container-grid').locator('.workspace-card-item').nth(1).click(); + await workspaces.locator('.workspaces-container-grid').locator('.workspace-card-item').nth(1).click(); } else if (mode === 'list') { - await toggleViewMode(connected); - await connected.locator('.workspaces-container').locator('.workspace-list-item').nth(1).click(); + await toggleViewMode(workspaces); + await workspaces.locator('.workspaces-container').locator('.workspace-list-item').nth(1).click(); } else { - await connected.locator('.sidebar').locator('.list-sidebar.workspaces').getByRole('listitem').nth(0).click(); + await workspaces.locator('.workspaces-container-grid').locator('.workspace-card-item').nth(1).click(); + await workspaces.locator('#connected-header').locator('.topbar-left').locator('ion-breadcrumb').nth(0).click(); + await workspaces.locator('.sidebar').locator('.list-sidebar.workspaces').getByRole('listitem').nth(0).click(); } - await expect(connected).toHaveHeader(['Trademeet'], true, true); + await expect(workspaces).toHaveHeader(['Trademeet'], true, true); }); - msTest(`Rename a workspace ${mode}`, async ({ connected }) => { - await openContextMenu(connected, mode as Mode); - const popover = connected.locator('.workspace-context-menu'); + msTest.fail(`Rename a workspace ${mode}`, async ({ workspaces }) => { + await openContextMenu(workspaces, mode as Mode, OpenMenuMethod.Button); + const popover = workspaces.locator('.workspace-context-menu'); await popover.getByRole('listitem').nth(1).click(); - await fillInputModal(connected, 'New Workspace Name', true); - await expect(connected).toShowToast('Workspace has been successfully renamed to New Workspace Name.', 'Success'); + await fillInputModal(workspaces, 'New Workspace Name', true); + await expect(workspaces).toShowToast('Workspace has been successfully renamed to New Workspace Name.', 'Success'); }); - msTest(`Check copy link workspace action with permission ${mode}`, async ({ connected, context }) => { + msTest.fail(`Check copy link workspace action with permission ${mode}`, async ({ workspaces, context }) => { await context.grantPermissions(['clipboard-write']); - await openContextMenu(connected, mode as Mode); - const contextMenu = connected.locator('.workspace-context-menu'); + await openContextMenu(workspaces, mode as Mode, OpenMenuMethod.Button); + const contextMenu = workspaces.locator('.workspace-context-menu'); await expect(contextMenu).toBeVisible(); await expect(contextMenu.getByRole('group').nth(1).getByRole('listitem').nth(1)).toHaveText('Copy link'); await contextMenu.getByRole('group').nth(1).getByRole('listitem').nth(1).click(); - await expect(connected).toShowToast('Workspace link has been copied to clipboard.', 'Info'); + await expect(workspaces).toShowToast('Workspace link has been copied to clipboard.', 'Info'); // cspell:disable-next-line const payload = 'k8QY94a350f2f629403db2269c44583f7aa1AcQ0Zkd8YbWfYF19LMwc55HjBOvI8LA8c_9oU2xaBJ0u2Ou0AFZYA4-QHhi2FprzAtUoAgMYwg'; const link = `parsec3://parsec.cloud/Org?a=path&p=${payload}`; - expect(await getClipboardText(connected)).toBe(link); + expect(await getClipboardText(workspaces)).toBe(link); }); - msTest(`Check copy link workspace action without permission ${mode}`, async ({ connected }) => { - await openContextMenu(connected, mode as Mode); - const contextMenu = connected.locator('.workspace-context-menu'); + msTest.fail(`Check copy link workspace action without permission ${mode}`, async ({ workspaces }) => { + await openContextMenu(workspaces, mode as Mode, OpenMenuMethod.Button); + const contextMenu = workspaces.locator('.workspace-context-menu'); await expect(contextMenu).toBeVisible(); await expect(contextMenu.getByRole('group').nth(1).getByRole('listitem').nth(1)).toHaveText('Copy link'); await contextMenu.getByRole('group').nth(1).getByRole('listitem').nth(1).click(); - await expect(connected).toShowToast('Failed to copy the link. Your browser or device does not seem to support copy/paste.', 'Error'); + await expect(workspaces).toShowToast('Failed to copy the link. Your browser or device does not seem to support copy/paste.', 'Error'); }); - msTest(`Toggle workspace favorite ${mode}`, async ({ connected }) => { - const favorites = connected.locator('.sidebar').locator('.favorites'); + msTest(`Toggle workspace favorite ${mode}`, async ({ workspaces }) => { + const favorites = workspaces.locator('.sidebar').locator('.favorites'); await expect(favorites).toBeHidden(); - await openContextMenu(connected, mode as Mode); - const popover = connected.locator('.workspace-context-menu'); + await openContextMenu(workspaces, mode as Mode, OpenMenuMethod.Button); + const popover = workspaces.locator('.workspace-context-menu'); await popover.getByRole('listitem').nth(7).click(); let wk; - if (await isInGridMode(connected)) { - wk = connected.locator('.workspaces-container-grid').locator('.workspace-card-item').nth(0); + if (await isInGridMode(workspaces)) { + wk = workspaces.locator('.workspaces-container-grid').locator('.workspace-card-item').nth(0); await expect(wk.locator('.workspace-card__title')).toHaveText('Trademeet'); } else { - wk = connected.locator('.workspaces-container').locator('.workspace-list-item').nth(0); + wk = workspaces.locator('.workspaces-container').locator('.workspace-list-item').nth(0); await expect(wk.locator('.workspace-name')).toHaveText('Trademeet'); } await expect(wk.locator('.workspace-favorite-icon')).toHaveTheClass('workspace-favorite-icon__on'); @@ -165,12 +176,12 @@ for (const mode of ['grid', 'list', 'sidebar']) { await expect(favorites.getByRole('listitem').nth(0)).toHaveText('Trademeet'); }); - msTest(`Open workspace sharing ${mode}`, async ({ connected }) => { - await expect(connected.locator('.workspace-sharing-modal')).toBeHidden(); - await openContextMenu(connected, mode as Mode); - const popover = connected.locator('.workspace-context-menu'); + msTest(`Open workspace sharing ${mode}`, async ({ workspaces }) => { + await expect(workspaces.locator('.workspace-sharing-modal')).toBeHidden(); + await openContextMenu(workspaces, mode as Mode, OpenMenuMethod.Button); + const popover = workspaces.locator('.workspace-context-menu'); await popover.getByRole('listitem').nth(5).click(); - await expect(connected.locator('.workspace-sharing-modal')).toBeVisible(); - await expect(connected.locator('.workspace-sharing-modal').locator('.ms-modal-header__title')).toHaveText('Trademeet'); + await expect(workspaces.locator('.workspace-sharing-modal')).toBeVisible(); + await expect(workspaces.locator('.workspace-sharing-modal').locator('.ms-modal-header__title')).toHaveText('Trademeet'); }); } diff --git a/client/tests/e2e/specs/workspaces_list.spec.ts b/client/tests/e2e/specs/workspaces_list.spec.ts index 36a61eae062..31ed711d3a2 100644 --- a/client/tests/e2e/specs/workspaces_list.spec.ts +++ b/client/tests/e2e/specs/workspaces_list.spec.ts @@ -15,7 +15,7 @@ async function toggleViewMode(page: Page): Promise<void> { } } -const workspaces = [ +const WORKSPACES = [ { name: 'The Copper Coronet', sharedWith: ['Ko', 'Ce'], @@ -30,33 +30,19 @@ const workspaces = [ }, ]; -msTest('List the workspaces', async ({ connected }) => { - const actionBar = connected.locator('#workspaces-ms-action-bar'); - await expect(actionBar.locator('.ms-action-bar-button')).toHaveCount(1); - await expect(actionBar.locator('#button-new-workspace')).toHaveText('New workspace'); - await expect(actionBar.locator('.counter')).toHaveText('3 items'); - await expect(actionBar.locator('#workspace-filter-select')).toHaveText('Name'); - await expect(actionBar.locator('.ms-grid-list-toggle').locator('#grid-view')).toHaveDisabledAttribute(); - await expect(actionBar.locator('.ms-grid-list-toggle').locator('#list-view')).toBeEnabled(); - await expect(connected.locator('.workspace-card-item')).toHaveCount(3); -}); - -for (const workspace of workspaces) { - msTest(`Check workspace card of ${workspace.name}`, async ({ connected }) => { - const workspaceCard = connected.locator('.workspace-card-item', { hasText: workspace.name }); +for (const workspace of WORKSPACES) { + msTest(`Check workspace card of ${workspace.name}`, async ({ workspaces }) => { + const workspaceCard = workspaces.locator('.workspace-card-item', { hasText: workspace.name }); await expect(workspaceCard).toContainText(workspace.name); expect(workspaceCard).toBeDefined(); const workspaceInfo = workspaceCard.locator('.workspace-info'); - if (workspace.sharedWith.length === 0) { - await expect(workspaceInfo.locator('.shared-group')).toBeHidden(); - await expect(workspaceInfo.locator('.not-shared-label')).toBeVisible(); - await expect(workspaceInfo.locator('.not-shared-label')).toHaveText('Not shared'); - } else { - await expect(workspaceInfo.locator('.shared-group')).toBeVisible(); - await expect(workspaceInfo.locator('.not-shared-label')).toBeHidden(); - await expect(workspaceInfo.locator('.shared-group').locator('.person-avatar')).toHaveCount(workspace.sharedWith.length); - await expect(workspaceInfo.locator('.shared-group').locator('.person-avatar')).toHaveText(workspace.sharedWith); - } + await expect(workspaceInfo.locator('.shared-group')).toBeHidden(); + await expect(workspaceInfo.locator('.not-shared-label')).toBeVisible(); + await expect(workspaceInfo.locator('.not-shared-label')).toHaveText('Not shared'); + // await expect(workspaceInfo.locator('.shared-group')).toBeVisible(); + // await expect(workspaceInfo.locator('.not-shared-label')).toBeHidden(); + // await expect(workspaceInfo.locator('.shared-group').locator('.person-avatar')).toHaveCount(workspace.sharedWith.length); + // await expect(workspaceInfo.locator('.shared-group').locator('.person-avatar')).toHaveText(workspace.sharedWith); const workspaceRole = workspaceCard.locator('.card-bottom'); await expect(workspaceRole.locator('.card-bottom__role')).toHaveText(/^(Reader|Manager|Owner|Contributor)$/); const role = await workspaceRole.locator('.card-bottom__role').textContent(); @@ -95,23 +81,51 @@ for (const workspace of workspaces) { } for (const gridMode of [false, true]) { - msTest(`Workspace sort order in ${gridMode ? 'grid' : 'list'} mode`, async ({ connected }) => { + msTest(`Empty workspaces in ${gridMode ? 'grid' : 'list'} mode`, async ({ connected }) => { if (!gridMode) { await toggleViewMode(connected); } + const actionBar = connected.locator('#workspaces-ms-action-bar'); + await expect(actionBar.locator('.ms-action-bar-button')).toHaveCount(1); + await expect(actionBar.locator('#button-new-workspace')).toHaveText('New workspace'); + await expect(actionBar.locator('.counter')).toHaveText('No items'); + await expect(actionBar.locator('#workspace-filter-select')).toHaveText('Name'); + if (gridMode) { + await expect(actionBar.locator('.ms-grid-list-toggle').locator('#grid-view')).toHaveDisabledAttribute(); + await expect(actionBar.locator('.ms-grid-list-toggle').locator('#list-view')).toBeEnabled(); + await expect(connected.locator('.workspaces-container').locator('.workspace-card-item')).toHaveCount(0); + await expect(connected.locator('.workspaces-container').locator('.no-workspaces-content')).toBeVisible(); + await expect(connected.locator('.workspaces-container').locator('.no-workspaces-content').locator('ion-text')).toHaveText( + 'You do not have access to any workspace yet. Workspaces that you create or have been shared with you will be listed here.', + ); + } else { + await expect(actionBar.locator('.ms-grid-list-toggle').locator('#grid-view')).toBeEnabled(); + await expect(actionBar.locator('.ms-grid-list-toggle').locator('#list-view')).toHaveDisabledAttribute(); + await expect(connected.locator('.workspaces-container').locator('.no-workspaces-content')).toBeVisible(); + await expect(connected.locator('.workspaces-container').locator('.workspace-list-item')).toHaveCount(0); + await expect(connected.locator('.workspaces-container').locator('.no-workspaces-content').locator('ion-text')).toHaveText( + 'You do not have access to any workspace yet. Workspaces that you create or have been shared with you will be listed here.', + ); + } + }); + + msTest(`Workspace sort order in ${gridMode ? 'grid' : 'list'} mode`, async ({ workspaces }) => { + if (!gridMode) { + await toggleViewMode(workspaces); + } // Order by name asc (default) - let names = workspaces.map((w) => w.name).sort((wName1, wName2) => wName1.localeCompare(wName2)); + let names = WORKSPACES.map((w) => w.name).sort((wName1, wName2) => wName1.localeCompare(wName2)); if (gridMode) { - await expect(connected.locator('.workspaces-container').locator('.workspace-card__title')).toHaveText(names); + await expect(workspaces.locator('.workspaces-container').locator('.workspace-card__title')).toHaveText(names); } else { - await expect(connected.locator('.workspaces-container').locator('.workspace-name__label')).toHaveText(names); + await expect(workspaces.locator('.workspaces-container').locator('.workspace-name__label')).toHaveText(names); } - const actionBar = connected.locator('#workspaces-ms-action-bar'); + const actionBar = workspaces.locator('#workspaces-ms-action-bar'); const sortSelector = actionBar.locator('#workspace-filter-select'); await expect(sortSelector).toHaveText('Name'); - await expect(connected.locator('.popover-viewport')).toBeHidden(); + await expect(workspaces.locator('.popover-viewport')).toBeHidden(); await sortSelector.click(); - const popover = connected.locator('.popover-viewport'); + const popover = workspaces.locator('.popover-viewport'); const sortItems = popover.getByRole('listitem'); await expect(sortItems).toHaveCount(2); await expect(sortItems).toHaveText(['Ascending', 'Name']); @@ -123,16 +137,16 @@ for (const gridMode of [false, true]) { } } await sortItems.nth(0).click(); - await expect(connected.locator('.popover-viewport')).toBeHidden(); + await expect(workspaces.locator('.popover-viewport')).toBeHidden(); // Order by name desc - names = workspaces.map((w) => w.name).sort((wName1, wName2) => wName2.localeCompare(wName1)); + names = WORKSPACES.map((w) => w.name).sort((wName1, wName2) => wName2.localeCompare(wName1)); await sortSelector.click(); if (gridMode) { - await expect(connected.locator('.workspaces-container').locator('.workspace-card__title')).toHaveText(names); + await expect(workspaces.locator('.workspaces-container').locator('.workspace-card__title')).toHaveText(names); } else { - await expect(connected.locator('.workspaces-container').locator('.workspace-name__label')).toHaveText(names); + await expect(workspaces.locator('.workspaces-container').locator('.workspace-name__label')).toHaveText(names); } - await expect(connected.locator('.popover-viewport').getByRole('listitem').nth(0)).toHaveText('Descending'); + await expect(workspaces.locator('.popover-viewport').getByRole('listitem').nth(0)).toHaveText('Descending'); }); } @@ -156,51 +170,51 @@ async function ensureFavorite(page: Page, favoritesCount: number): Promise<void> } } -msTest('Checks favorites', async ({ connected }) => { - await expect(connected.locator('.workspace-card-item').locator('.workspace-card__title')).toHaveText([ +msTest('Checks favorites', async ({ workspaces }) => { + await expect(workspaces.locator('.workspace-card-item').locator('.workspace-card__title')).toHaveText([ 'The Copper Coronet', 'Trademeet', "Watcher's Keep", ]); - await ensureFavorite(connected, 0); - await connected.locator('.workspace-card-item').nth(1).locator('.workspace-favorite-icon').click(); + await ensureFavorite(workspaces, 0); + await workspaces.locator('.workspace-card-item').nth(1).locator('.workspace-favorite-icon').click(); // Put favorite in first - await expect(connected.locator('.workspace-card-item').locator('.workspace-card__title')).toHaveText([ + await expect(workspaces.locator('.workspace-card-item').locator('.workspace-card__title')).toHaveText([ 'Trademeet', 'The Copper Coronet', "Watcher's Keep", ]); - await ensureFavorite(connected, 1); + await ensureFavorite(workspaces, 1); // Check in list mode too - await toggleViewMode(connected); - await ensureFavorite(connected, 1); + await toggleViewMode(workspaces); + await ensureFavorite(workspaces, 1); - await connected.locator('.workspaces-container').locator('.workspace-list-item').nth(1).locator('.workspace-favorite-icon').click(); - await expect(connected.locator('.workspace-list-item').locator('.workspace-name__label')).toHaveText([ + await workspaces.locator('.workspaces-container').locator('.workspace-list-item').nth(1).locator('.workspace-favorite-icon').click(); + await expect(workspaces.locator('.workspace-list-item').locator('.workspace-name__label')).toHaveText([ 'The Copper Coronet', 'Trademeet', "Watcher's Keep", ]); - await ensureFavorite(connected, 2); + await ensureFavorite(workspaces, 2); // Check in grid mode too - await toggleViewMode(connected); - await ensureFavorite(connected, 2); + await toggleViewMode(workspaces); + await ensureFavorite(workspaces, 2); - await connected.locator('.workspace-card-item').nth(1).locator('.workspace-favorite-icon').click(); - await ensureFavorite(connected, 1); - await toggleViewMode(connected); + await workspaces.locator('.workspace-card-item').nth(1).locator('.workspace-favorite-icon').click(); + await ensureFavorite(workspaces, 1); + await toggleViewMode(workspaces); - await connected.locator('.workspaces-container').locator('.workspace-list-item').nth(0).locator('.workspace-favorite-icon').click(); - await ensureFavorite(connected, 0); + await workspaces.locator('.workspaces-container').locator('.workspace-list-item').nth(0).locator('.workspace-favorite-icon').click(); + await ensureFavorite(workspaces, 0); }); for (const gridMode of [false, true]) { - msTest(`Workspace filter in ${gridMode ? 'grid' : 'list'} mode`, async ({ connected }) => { + msTest(`Workspace filter in ${gridMode ? 'grid' : 'list'} mode`, async ({ workspaces }) => { if (!gridMode) { - await toggleViewMode(connected); + await toggleViewMode(workspaces); } - const searchInput = connected.locator('#workspaces-ms-action-bar').locator('#search-input-workspace').locator('ion-input'); - const container = connected.locator('.workspaces-container'); + const searchInput = workspaces.locator('#workspaces-ms-action-bar').locator('#search-input-workspace').locator('ion-input'); + const container = workspaces.locator('.workspaces-container'); const titles = gridMode ? container.locator('.workspace-card__title') : container.locator('.workspace-name__label'); await expect(titles).toHaveText(['The Copper Coronet', 'Trademeet', "Watcher's Keep"]); @@ -209,33 +223,33 @@ for (const gridMode of [false, true]) { await fillIonInput(searchInput, 'eep'); await expect(titles).toHaveText(["Watcher's Keep"]); await fillIonInput(searchInput, ''); - await expect(connected.locator('.no-workspaces')).not.toBeVisible(); + await expect(workspaces.locator('.no-workspaces')).not.toBeVisible(); await expect(titles).toHaveText(['The Copper Coronet', 'Trademeet', "Watcher's Keep"]); await fillIonInput(searchInput, 'No match'); await expect(titles).not.toBeVisible(); - await expect(connected.locator('.no-workspaces')).toBeVisible(); - await expect(connected.locator('.no-workspaces').locator('ion-text')).toHaveText('No workspace match this search filter.'); + await expect(workspaces.locator('.no-workspaces')).toBeVisible(); + await expect(workspaces.locator('.no-workspaces').locator('ion-text')).toHaveText('No workspace match this search filter.'); }); } -msTest('Back from files with back button', async ({ connected }) => { - await connected.locator('.workspace-card-item').nth(0).click(); - await expect(connected.locator('.topbar-left').locator('.topbar-left__breadcrumb').locator('ion-breadcrumb').nth(1)).toHaveText( +msTest('Back from files with back button', async ({ workspaces }) => { + await workspaces.locator('.workspace-card-item').nth(0).click(); + await expect(workspaces.locator('.topbar-left').locator('.topbar-left__breadcrumb').locator('ion-breadcrumb').nth(1)).toHaveText( 'The Copper Coronet', ); - await connected.locator('.topbar-left').locator('.back-button').click(); - await expect(connected.locator('.topbar-left').locator('.topbar-left__breadcrumb').locator('ion-breadcrumb').nth(0)).toHaveText( + await workspaces.locator('.topbar-left').locator('.back-button').click(); + await expect(workspaces.locator('.topbar-left').locator('.topbar-left__breadcrumb').locator('ion-breadcrumb').nth(0)).toHaveText( 'My workspaces', ); }); -msTest('Back from files with side menu', async ({ connected }) => { - await connected.locator('.workspace-card-item').nth(0).click(); - await expect(connected.locator('.topbar-left').locator('.topbar-left__breadcrumb').locator('ion-breadcrumb').nth(1)).toHaveText( +msTest('Back from files with side menu', async ({ workspaces }) => { + await workspaces.locator('.workspace-card-item').nth(0).click(); + await expect(workspaces.locator('.topbar-left').locator('.topbar-left__breadcrumb').locator('ion-breadcrumb').nth(1)).toHaveText( 'The Copper Coronet', ); - await connected.locator('.sidebar').locator('.sidebar-header').locator('#goHome').click(); - await expect(connected.locator('.topbar-left').locator('.topbar-left__breadcrumb').locator('ion-breadcrumb').nth(0)).toHaveText( + await workspaces.locator('.sidebar').locator('.sidebar-header').locator('#goHome').click(); + await expect(workspaces.locator('.topbar-left').locator('.topbar-left__breadcrumb').locator('ion-breadcrumb').nth(0)).toHaveText( 'My workspaces', ); });