diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModel.kt index 7948bd90ec64..7767fd7d51b0 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModel.kt @@ -13,14 +13,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import org.wordpress.android.Constants.TYPE_DOMAINS_PRODUCT import org.wordpress.android.R -import org.wordpress.android.fluxc.Dispatcher -import org.wordpress.android.fluxc.model.products.Product -import org.wordpress.android.fluxc.network.rest.wpcom.site.DomainSuggestionResponse -import org.wordpress.android.fluxc.store.ProductsStore -import org.wordpress.android.fluxc.store.SiteStore.OnSuggestedDomains -import org.wordpress.android.fluxc.store.SiteStore.SuggestDomainErrorType import org.wordpress.android.models.networkresource.ListState import org.wordpress.android.models.networkresource.ListState.Error import org.wordpress.android.models.networkresource.ListState.Loading @@ -41,14 +34,15 @@ import org.wordpress.android.ui.sitecreation.misc.SiteCreationSearchInputUiState import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.usecases.FETCH_DOMAINS_VENDOR_DOT import org.wordpress.android.ui.sitecreation.usecases.FETCH_DOMAINS_VENDOR_MOBILE +import org.wordpress.android.ui.sitecreation.usecases.FetchDomainsResult import org.wordpress.android.ui.sitecreation.usecases.FetchDomainsUseCase import org.wordpress.android.ui.utils.UiString import org.wordpress.android.ui.utils.UiString.UiStringRes import org.wordpress.android.ui.utils.UiString.UiStringText -import org.wordpress.android.util.AppLog import org.wordpress.android.util.NetworkUtilsWrapper import org.wordpress.android.util.config.PlansInSiteCreationFeatureConfig import org.wordpress.android.viewmodel.SingleLiveEvent +import uniffi.wp_api.DomainSuggestion import javax.inject.Inject import javax.inject.Named import kotlin.coroutines.CoroutineContext @@ -60,10 +54,8 @@ private const val ERROR_CONTEXT = "domains" @HiltViewModel class SiteCreationDomainsViewModel @Inject constructor( private val networkUtils: NetworkUtilsWrapper, - private val dispatcher: Dispatcher, private val domainSanitizer: SiteCreationDomainSanitizer, private val fetchDomainsUseCase: FetchDomainsUseCase, - private val productsStore: ProductsStore, private val plansInSiteCreationFeatureConfig: PlansInSiteCreationFeatureConfig, private val tracker: SiteCreationTracker, @Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher, @@ -78,7 +70,6 @@ class SiteCreationDomainsViewModel @Inject constructor( private val _uiState: MutableLiveData = MutableLiveData() val uiState: LiveData = _uiState - private var products: Map = mapOf() private var currentQuery: DomainSuggestionsQuery? = null private var listState: ListState = ListState.Init() private var selectedDomain by Delegates.observable(null) { _, old, new -> @@ -96,36 +87,11 @@ class SiteCreationDomainsViewModel @Inject constructor( private val _onHelpClicked = SingleLiveEvent() val onHelpClicked: LiveData = _onHelpClicked - init { - dispatcher.register(fetchDomainsUseCase) - } - - override fun onCleared() { - super.onCleared() - dispatcher.unregister(fetchDomainsUseCase) - } - fun start() { if (isStarted) return isStarted = true tracker.trackDomainsAccessed() resetUiState() - if (plansInSiteCreationFeatureConfig.isEnabled()) fetchAndCacheProducts() - } - - private fun fetchAndCacheProducts() { - launch { - val result = productsStore.fetchProducts(TYPE_DOMAINS_PRODUCT) - when { - result.isError -> { - AppLog.e(AppLog.T.DOMAIN_REGISTRATION, "Error while fetching domain products: ${result.error}") - } - - else -> { - products = result.products.orEmpty().associateBy { it.productId } - } - } - } } fun onCreateSiteBtnClicked() { @@ -159,10 +125,12 @@ class SiteCreationDomainsViewModel @Inject constructor( updateUiStateToContent(query, Loading(Ready(emptyList()), false)) fetchDomainsJob = launch { delay(THROTTLE_DELAY) - val onSuggestedDomains: OnSuggestedDomains = fetchDomainsByPurchasingFeatureConfig(query.value) + val onlyWordpressCom = !plansInSiteCreationFeatureConfig.isEnabled() + val vendor = if (onlyWordpressCom) FETCH_DOMAINS_VENDOR_DOT else FETCH_DOMAINS_VENDOR_MOBILE + val result = fetchDomainsUseCase.fetchDomains(query.value, vendor, onlyWordpressCom) withContext(mainDispatcher) { - onDomainsFetched(query, onSuggestedDomains) + onDomainsFetched(query, result) } } } else { @@ -174,55 +142,52 @@ class SiteCreationDomainsViewModel @Inject constructor( } } - private suspend fun fetchDomainsByPurchasingFeatureConfig(query: String): OnSuggestedDomains { - val onlyWordpressCom = !plansInSiteCreationFeatureConfig.isEnabled() - val vendor = if (onlyWordpressCom) FETCH_DOMAINS_VENDOR_DOT else FETCH_DOMAINS_VENDOR_MOBILE - - return fetchDomainsUseCase.fetchDomains(query, vendor, onlyWordpressCom) - } + private fun onDomainsFetched(query: DomainSuggestionsQuery, result: FetchDomainsResult) { + when (result) { + is FetchDomainsResult.Error -> { + tracker.trackErrorShown(ERROR_CONTEXT, result.type, result.message) + updateUiStateToContent( + query, + Error( + listState, + errorMessageResId = R.string.site_creation_fetch_suggestions_error_unknown + ) + ) + } + FetchDomainsResult.InvalidQuery -> { + val emptyListMessage = UiStringRes( + R.string.new_site_creation_empty_domain_list_message_invalid_query + ) + updateUiStateToContent(query, Success(emptyList()), emptyListMessage) + } + is FetchDomainsResult.Success -> { + val domains = result.suggestions.map(::parseSuggestion) + .partition { it.domainName.startsWith("${query.value}.") } + .toList().flatten() - private fun onDomainsFetched(query: DomainSuggestionsQuery, event: OnSuggestedDomains) { - // We want to treat `INVALID_QUERY` as if it's an empty result, so we'll ignore it - if (event.isError && event.error.type != SuggestDomainErrorType.INVALID_QUERY) { - tracker.trackErrorShown( - ERROR_CONTEXT, - event.error.type.toString(), - event.error.message - ) - updateUiStateToContent( - query, - Error( - listState, - errorMessageResId = R.string.site_creation_fetch_suggestions_error_unknown + val emptyListMessage = UiStringRes( + R.string.new_site_creation_empty_domain_list_message ) - ) - } else { - /** - * We would like to show the domains that matches the current query at the top. For this, we split the - * domains into two, one part for the domain names that start with the current query plus `.` and the - * other part for the others. We then combine them back again into a single list. - */ - val domains = event.suggestions.map(::parseSuggestion) - .partition { it.domainName.startsWith("${query.value}.") } - .toList().flatten() - - val isInvalidQuery = event.isError && event.error.type == SuggestDomainErrorType.INVALID_QUERY - val emptyListMessage = UiStringRes( - if (isInvalidQuery) R.string.new_site_creation_empty_domain_list_message_invalid_query - else R.string.new_site_creation_empty_domain_list_message - ) - updateUiStateToContent(query, Success(domains), emptyListMessage) + updateUiStateToContent(query, Success(domains), emptyListMessage) + } } } - private fun parseSuggestion(response: DomainSuggestionResponse): DomainModel = with(response) { - DomainModel( - domainName = domain_name, - isFree = is_free, - cost = cost.orEmpty(), - productId = product_id, - supportsPrivacy = supports_privacy, + private fun parseSuggestion(suggestion: DomainSuggestion): DomainModel = when (suggestion) { + is DomainSuggestion.Free -> DomainModel( + domainName = suggestion.v1.domainName, + isFree = true, + cost = suggestion.v1.cost, + productId = 0, + supportsPrivacy = false, + ) + is DomainSuggestion.Paid -> DomainModel( + domainName = suggestion.v1.domainName, + isFree = false, + cost = suggestion.v1.cost, + productId = suggestion.v1.productId.toInt(), + supportsPrivacy = suggestion.v1.supportsPrivacy, ) } @@ -514,11 +479,6 @@ private fun createSearchInputUiState( R.color.purple_50, UiStringRes(R.string.site_creation_domain_tag_best_alternative), ) - - object Sale : Tag( - R.color.yellow_50, - UiStringRes(R.string.site_creation_domain_tag_sale) - ) } sealed class Cost(val title: UiString) { @@ -530,13 +490,6 @@ private fun createSearchInputUiState( val strikeoutTitle = UiStringText(titleCost) val subtitle = UiStringRes(R.string.site_creation_domain_free_with_annual_plan) } - - data class OnSale(private val titleCost: String, private val strikeoutTitleCost: String) : Cost( - UiStringText(titleCost) - ) { - val strikeoutTitle = UiStringText(strikeoutTitleCost) - val subtitle = UiStringRes(R.string.site_creation_domain_cost_sale) - } } } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/compose/DomainItem.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/compose/DomainItem.kt index d90a744ca9e4..6438a446d12f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/compose/DomainItem.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/compose/DomainItem.kt @@ -40,7 +40,6 @@ import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewMode import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.ListItemUiState.New.DomainUiState.Cost import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.ListItemUiState.New.DomainUiState.Tag.BestAlternative import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.ListItemUiState.New.DomainUiState.Tag.Recommended -import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.ListItemUiState.New.DomainUiState.Tag.Sale import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.ListItemUiState.New.DomainUiState.Tag.Unavailable private val HighlightBgColor @Composable get() = colorScheme.primary.copy(0.1f) @@ -107,14 +106,7 @@ fun DomainItem(uiState: DomainUiState): Unit = with(uiState) { } } if (tags.none { it is Unavailable }) { - if (cost is Cost.OnSale) { - SalePrice( - cost.strikeoutTitle.asString() to cost.title.asString(), - cost.subtitle.asString(), - modifier = Modifier.padding(start = Margin.ExtraLarge.value) - ) - } - else if (cost is Cost.Paid) { + if (cost is Cost.Paid) { Plan( cost.strikeoutTitle.asString() to cost.title.asString(), modifier = Modifier.padding(start = Margin.ExtraLarge.value) @@ -151,36 +143,6 @@ private fun Price(text: String, modifier: Modifier = Modifier) { ) } -@Composable -private fun SalePrice(title: Pair, subtitle: String, modifier: Modifier = Modifier) { - Column( - modifier, - horizontalAlignment = Alignment.End, - ) { - title.let { (strikethroughText, normalText) -> - Row(verticalAlignment = Alignment.Bottom) { - Text( - strikethroughText, - color = SecondaryTextColor, - fontSize = SecondaryFontSize, - textDecoration = TextDecoration.LineThrough, - modifier = Modifier.padding(end = 4.dp) - ) - Text( - normalText, - color = colorScheme.primary, - fontSize = PrimaryFontSize, - ) - } - } - Text( - subtitle, - color = colorScheme.primary, - fontSize = SecondaryFontSize, - ) - } -} - @Composable private fun Plan(title: Pair, modifier: Modifier = Modifier) { Column( @@ -213,7 +175,6 @@ private fun DomainItemPreview() { }, cost = when { it % 3 == 0 -> Cost.Paid("$${it * 5}") - it in 1..2 -> Cost.OnSale("$${it * 2}", "$${it * 3}") else -> Cost.Free }, tags = listOfNotNull( @@ -223,7 +184,6 @@ private fun DomainItemPreview() { 2 -> BestAlternative else -> null }, - if (it in 1..2) Sale else null, ), isSelected = it == 5, onClick = {} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/usecases/FetchDomainsUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/usecases/FetchDomainsUseCase.kt index 32fdeffc6486..282f9fd92925 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/usecases/FetchDomainsUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/usecases/FetchDomainsUseCase.kt @@ -1,66 +1,103 @@ package org.wordpress.android.ui.sitecreation.usecases -import kotlinx.coroutines.suspendCancellableCoroutine -import org.greenrobot.eventbus.Subscribe -import org.greenrobot.eventbus.ThreadMode -import org.wordpress.android.fluxc.Dispatcher -import org.wordpress.android.fluxc.generated.SiteActionBuilder -import org.wordpress.android.fluxc.store.SiteStore -import org.wordpress.android.fluxc.store.SiteStore.OnSuggestedDomains -import org.wordpress.android.fluxc.store.SiteStore.SuggestDomainsPayload +import org.wordpress.android.fluxc.store.AccountStore +import org.wordpress.android.networking.restapi.WpComApiClientProvider +import org.wordpress.android.util.AppLog +import rs.wordpress.api.kotlin.WpComApiClient +import rs.wordpress.api.kotlin.WpRequestResult +import uniffi.wp_api.DomainSuggestion +import uniffi.wp_api.DomainSuggestionsParams +import uniffi.wp_api.WpErrorCode import javax.inject.Inject -import kotlin.coroutines.Continuation -import kotlin.coroutines.resume const val FETCH_DOMAINS_VENDOR_DOT = "dot" const val FETCH_DOMAINS_VENDOR_MOBILE = "mobile" -private const val FETCH_DOMAINS_SIZE = 20 +private const val FETCH_DOMAINS_SIZE = 20u +private const val ERROR_CODE_INVALID_QUERY = "invalid_query" +private const val ERROR_CODE_EMPTY_RESULTS = "empty_results" +private const val ERROR_TYPE_GENERIC = "GENERIC_ERROR" +private const val ERROR_TYPE_NO_ACCESS_TOKEN = "NO_ACCESS_TOKEN" -/** - * Transforms newSuggestDomainsAction EventBus event to a coroutine. - * - * The client may dispatch multiple requests, but we want to accept only the latest one and ignore all others. - * We can't rely just on job.cancel() as the OnSuggestedDomains may have already been dispatched and FluxC will - * return a result. - */ class FetchDomainsUseCase @Inject constructor( - val dispatcher: Dispatcher, - @Suppress("unused") val siteStore: SiteStore + private val wpComApiClientProvider: WpComApiClientProvider, + private val accountStore: AccountStore, ) { + private var wpComApiClient: WpComApiClient? = null + /** - * Query - Continuation pair + * Null when there is no WordPress.com account to make the request as. + * + * `AccountStore.accessToken` is typed nullable but reads `""` when signed + * out, and is only null between an in-process sign out and the next + * launch, so both have to be treated as no token. */ - private var pair: Pair>? = null + @Synchronized + private fun getOrCreateClient(): WpComApiClient? { + val token = accountStore.accessToken?.takeIf { it.isNotEmpty() } ?: return null + return wpComApiClient + ?: wpComApiClientProvider.getWpComApiClient(token) + .also { wpComApiClient = it } + } suspend fun fetchDomains( query: String, vendor: String, onlyWordpressCom: Boolean, - size: Int = FETCH_DOMAINS_SIZE - ): OnSuggestedDomains { - val payload = SuggestDomainsPayload( - query, - size, - vendor, - onlyWordpressCom, - includeWordpressCom = true, - includeDotBlogSubdomain = false + ): FetchDomainsResult { + val client = getOrCreateClient() ?: run { + AppLog.e( + AppLog.T.DOMAIN_REGISTRATION, + "Cannot fetch domain suggestions without a WP.com access token" + ) + return FetchDomainsResult.Error(type = ERROR_TYPE_NO_ACCESS_TOKEN, message = null) + } + val params = DomainSuggestionsParams( + query = query, + quantity = FETCH_DOMAINS_SIZE, + vendor = vendor, + onlyWordpressdotcom = onlyWordpressCom, // checkstyle ignore + includeWordpressdotcom = true, // checkstyle ignore + includeDotblogsubdomain = false, ) - - return suspendCancellableCoroutine { cont -> - pair = Pair(payload.query, cont) - dispatcher.dispatch(SiteActionBuilder.newSuggestDomainsAction(payload)) + return when ( + val result = client + .request { it.domains().suggestions(params).data } + ) { + is WpRequestResult.Success -> + FetchDomainsResult.Success(result.response) + is WpRequestResult.WpError -> + when (val code = result.apiErrorCode()) { + ERROR_CODE_INVALID_QUERY -> FetchDomainsResult.InvalidQuery + // The API reports "no domains for that search" as an error, + // but there is nothing wrong with the request. + ERROR_CODE_EMPTY_RESULTS -> FetchDomainsResult.Success(emptyList()) + else -> FetchDomainsResult.Error( + type = code ?: ERROR_TYPE_GENERIC, + message = result.errorMessage, + ) + } + else -> FetchDomainsResult.Error(type = ERROR_TYPE_GENERIC, message = null) } } +} - @Subscribe(threadMode = ThreadMode.BACKGROUND) - @Suppress("unused") - fun onSuggestedDomains(event: OnSuggestedDomains) { - pair?.let { - if (event.query == it.first) { - it.second.resume(event) - pair = null - } - } - } +/** + * The API's own error code, for the codes this endpoint defines. Codes the + * WordPress REST API also uses are modelled as [WpErrorCode] variants and + * return null. + */ +private fun WpRequestResult.WpError<*>.apiErrorCode(): String? = + (errorCode as? WpErrorCode.CustomException)?.v1 + +sealed interface FetchDomainsResult { + data class Success( + val suggestions: List, + ) : FetchDomainsResult + + data object InvalidQuery : FetchDomainsResult + + data class Error( + val type: String, + val message: String?, + ) : FetchDomainsResult } diff --git a/WordPress/src/main/res/layout/site_creation_domains_screen.xml b/WordPress/src/main/res/layout/site_creation_domains_screen.xml index d42780a91d8f..bc9f27fecd15 100644 --- a/WordPress/src/main/res/layout/site_creation_domains_screen.xml +++ b/WordPress/src/main/res/layout/site_creation_domains_screen.xml @@ -3,8 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/content_layout" android:layout_width="match_parent" - android:layout_height="match_parent" - android:animateLayoutChanges="true"> + android:layout_height="match_parent"> diff --git a/WordPress/src/main/res/values-ar/strings.xml b/WordPress/src/main/res/values-ar/strings.xml index 0d530fac2dcc..0d2fd2c66b05 100644 --- a/WordPress/src/main/res/values-ar/strings.xml +++ b/WordPress/src/main/res/values-ar/strings.xml @@ -925,7 +925,6 @@ Language: ar YourSiteName.com البحث باستخدام الكلمات المفتاحية ابحث عن نطاق قصير لا يُنسى لمساعدة الأشخاص على العثور على موقعك وزيارته. - للعام الأول تم إنشاء موقعك على الويب بنجاح، لكننا واجهنا مشكلة في أثناء إعداد نطاقك المخصص للسداد. يرجى المحاولة مجددًا أو الاتصال بالدعم للحصول على المساعدة. قد يستغرق الأمر ما يصل إلى 30 دقيقة لكي يبدأ نطاقك المخصص بالعمل. لقد أرسلنا إليك الإيصال الخاص بك في رسالة عبر البريد الإلكتروني. %s @@ -989,7 +988,6 @@ Language: ar جذب مزيد من حركة المرور إلى موقعك باستخدام Blaze التوهج هذا النطاق مسجّل بالفعل - تخفيض موصى به أفضل بديل ارجع إلى قسم الأسئلة المتداولة لدينا للحصول على إجابات عن الأسئلة الشائعة التي قد تطرحها. diff --git a/WordPress/src/main/res/values-cs/strings.xml b/WordPress/src/main/res/values-cs/strings.xml index dc80aecfe444..ac2008301991 100644 --- a/WordPress/src/main/res/values-cs/strings.xml +++ b/WordPress/src/main/res/values-cs/strings.xml @@ -949,7 +949,6 @@ Language: cs_CZ NazevVasehoWebu.cz Hledat pomocí klíčových slov Hledejte krátkou a zapamatovatelnou doménu, která pomůže lidem najít a navštívit váš web. - za první rok Váš web byl úspěšně vytvořen, ale při přípravě vaší vlastní domény k pokladně jsme narazili na problém. Zkuste to prosím znovu nebo kontaktujte podporu. Správné fungování vaší vlastní domény může trvat až 30 minut. Zaslali jsme vám e-mailem účtenku. %s @@ -1013,7 +1012,6 @@ Language: cs_CZ Přiveďte na svůj web větší návštěvnost se zvýrazněním Zvýraznění Tato doména je již registrována - Prodej Doporučeno Nejlepší alternativa Odpovědi na běžné otázky, které můžete mít, najdete v našich FAQ. diff --git a/WordPress/src/main/res/values-de/strings.xml b/WordPress/src/main/res/values-de/strings.xml index c41612e9cfdb..7b67dc1dacbe 100644 --- a/WordPress/src/main/res/values-de/strings.xml +++ b/WordPress/src/main/res/values-de/strings.xml @@ -949,7 +949,6 @@ Language: de YourSiteName.com Mit Stichwörtern suchen Suche nach einer kurzen und einprägsamen Domain, damit Personen deine Website leicht finden und besuchen können. - für das erste Jahr Deine Website wurde erfolgreich erstellt. Wir haben jedoch ein Problem festgestellt, als wir deine individuelle Domain für den Bezahlvorgang vorbereitet haben. Bitte versuche es erneut oder kontaktiere den Support, um Hilfe zu erhalten. Es kann bis zu 30 Minuten dauern, bis deine individuelle Domain vollständig erreichbar ist. Wir haben dir deinen Beleg per E-Mail gesendet. %s @@ -1013,7 +1012,6 @@ Language: de Leite mit Blaze mehr Traffic auf deine Website Blaze Diese Domain ist bereits registriert - Angebot Empfohlen Beste Alternative In unseren FAQ findest du Antworten auf häufig gestellte Fragen. diff --git a/WordPress/src/main/res/values-el/strings.xml b/WordPress/src/main/res/values-el/strings.xml index 8f3968bc0fb3..9040e767ed0a 100644 --- a/WordPress/src/main/res/values-el/strings.xml +++ b/WordPress/src/main/res/values-el/strings.xml @@ -6,7 +6,6 @@ Generator: GlotPress/4.1.0 Language: el_GR --> - Προσφορά Προτεινόμενο Καλύτερη Εναλλακτική Βοήθεια diff --git a/WordPress/src/main/res/values-en-rCA/strings.xml b/WordPress/src/main/res/values-en-rCA/strings.xml index 8fe7cdd998e2..cbe358608dca 100644 --- a/WordPress/src/main/res/values-en-rCA/strings.xml +++ b/WordPress/src/main/res/values-en-rCA/strings.xml @@ -573,7 +573,6 @@ Language: en_CA YourSiteName.com Search with keywords Search for a short and memorable domain to help people find and visit your site. - for the first year Your website has been created successfully, but we encountered an issue while preparing your custom domain for checkout. Please try again or contact support for assistance. It may take up to 30 minutes for your custom domain to start working. We’ve emailed your receipt. %s @@ -635,7 +634,6 @@ Language: en_CA Help Free Logs - Sale Blaze Tickets Recommended diff --git a/WordPress/src/main/res/values-en-rGB/strings.xml b/WordPress/src/main/res/values-en-rGB/strings.xml index 224bcaeb6da9..a961dc7ea889 100644 --- a/WordPress/src/main/res/values-en-rGB/strings.xml +++ b/WordPress/src/main/res/values-en-rGB/strings.xml @@ -949,7 +949,6 @@ Language: en_GB YourSiteName.com Search with keywords Search for a short and memorable domain to help people find and visit your site. - for the first year Your website has been created successfully, but we encountered an issue while preparing your custom domain for checkout. Please try again or contact support for assistance. It may take up to 30 minutes for your custom domain to start working. We’ve emailed your receipt. %s @@ -1013,7 +1012,6 @@ Language: en_GB Drive more traffic to your site with Blaze Blaze This domain is already registered - Sale Recommended Best Alternative See our FAQ for answers to common questions you may have. diff --git a/WordPress/src/main/res/values-es-rCL/strings.xml b/WordPress/src/main/res/values-es-rCL/strings.xml index 2416e377c1b6..54eab0f067b1 100644 --- a/WordPress/src/main/res/values-es-rCL/strings.xml +++ b/WordPress/src/main/res/values-es-rCL/strings.xml @@ -468,7 +468,6 @@ Language: es_CL Elnombredetuweb.com Puede tardar hasta 30 minutos en que tu dominio personalizado empiece a funcionar. Te hemos mandado tu recibo por correo electrónico. %s - el primer año Busca una dominio corto y memorable para ayudar a la gente a encontrar y visitar tu sitio. Buscar con palabras clave Tu web ha sido creada con éxito, pero hemos encontrado un problema al preparar tu dominio personalizado al finalizar la compra. Por favor, inténtalo otra vez o contacta con nuestro soporte para obtener ayuda. @@ -536,7 +535,6 @@ Language: es_CL Registros Mejor alternativa Recomendado - Oferta Este dominio ya está registrado Con nuestras preguntas frecuentes podrás resolver algunas de tus dudas. ¡Gracias por cambiar a la aplicación Jetpack! diff --git a/WordPress/src/main/res/values-es-rCO/strings.xml b/WordPress/src/main/res/values-es-rCO/strings.xml index e98f97f33300..d53777fc6d39 100644 --- a/WordPress/src/main/res/values-es-rCO/strings.xml +++ b/WordPress/src/main/res/values-es-rCO/strings.xml @@ -949,7 +949,6 @@ Language: es_CO Elnombredetuweb.com Buscar con palabras clave Busca una dominio corto y memorable para ayudar a la gente a encontrar y visitar tu sitio. - el primer año Tu web ha sido creada con éxito, pero hemos encontrado un problema al preparar tu dominio personalizado al finalizar la compra. Por favor, inténtalo otra vez o contacta con nuestro soporte para obtener ayuda. Puede tardar hasta 30 minutos en que tu dominio personalizado empiece a funcionar. Te hemos mandado tu recibo por correo electrónico. %s @@ -1013,7 +1012,6 @@ Language: es_CO Genera más tráfico hacia tu sitio con Blaze Blaze Este dominio ya está registrado - Oferta Recomendado Mejor alternativa Con nuestras preguntas frecuentes podrás resolver algunas de tus dudas. diff --git a/WordPress/src/main/res/values-es/strings.xml b/WordPress/src/main/res/values-es/strings.xml index a5e45b60c849..4dd39568b0ab 100644 --- a/WordPress/src/main/res/values-es/strings.xml +++ b/WordPress/src/main/res/values-es/strings.xml @@ -949,7 +949,6 @@ Language: es Elnombredetuweb.com Buscar con palabras clave Busca una dominio corto y memorable para ayudar a la gente a encontrar y visitar tu sitio. - el primer año Tu web ha sido creada con éxito, pero hemos encontrado un problema al preparar tu dominio personalizado al finalizar la compra. Por favor, inténtalo otra vez o contacta con nuestro soporte para obtener ayuda. Puede tardar hasta 30 minutos en que tu dominio personalizado empiece a funcionar. Te hemos mandado tu recibo por correo electrónico. %s @@ -1013,7 +1012,6 @@ Language: es Genera más tráfico hacia tu sitio con Blaze Blaze Este dominio ya está registrado - Oferta Recomendado Mejor alternativa Con nuestras preguntas frecuentes podrás resolver algunas de tus dudas. diff --git a/WordPress/src/main/res/values-fr-rCA/strings.xml b/WordPress/src/main/res/values-fr-rCA/strings.xml index 4160e8f4dbe0..b50d744a7a26 100644 --- a/WordPress/src/main/res/values-fr-rCA/strings.xml +++ b/WordPress/src/main/res/values-fr-rCA/strings.xml @@ -923,7 +923,6 @@ Language: fr NomDeVotreSite.com Effectuer une recherche à l’aide de mots-clés Recherchez un domaine court et facile à retenir pour aider les internautes à trouver et visiter votre site. - la première année Votre site Web a été créé, mais nous avons rencontré un problème lors de la préparation de votre domaine personnalisé pour la validation de la commande. Réessayez ou contactez l’assistance pour obtenir de l’aide. Un délai de 30 minutes peut être nécessaire pour que votre domaine personnalisé soit opérationnel. Nous vous avons envoyé le reçu par e-mail. %s @@ -987,7 +986,6 @@ Language: fr Améliorer le trafic sur votre site avec Blaze Blaze Ce nom de domaine est déjà enregistré. - Promo Recommandé Meilleure alternative Notre FAQ comporte les réponses aux questions fréquentes que vous vous posez peut-être. diff --git a/WordPress/src/main/res/values-fr/strings.xml b/WordPress/src/main/res/values-fr/strings.xml index 4160e8f4dbe0..b50d744a7a26 100644 --- a/WordPress/src/main/res/values-fr/strings.xml +++ b/WordPress/src/main/res/values-fr/strings.xml @@ -923,7 +923,6 @@ Language: fr NomDeVotreSite.com Effectuer une recherche à l’aide de mots-clés Recherchez un domaine court et facile à retenir pour aider les internautes à trouver et visiter votre site. - la première année Votre site Web a été créé, mais nous avons rencontré un problème lors de la préparation de votre domaine personnalisé pour la validation de la commande. Réessayez ou contactez l’assistance pour obtenir de l’aide. Un délai de 30 minutes peut être nécessaire pour que votre domaine personnalisé soit opérationnel. Nous vous avons envoyé le reçu par e-mail. %s @@ -987,7 +986,6 @@ Language: fr Améliorer le trafic sur votre site avec Blaze Blaze Ce nom de domaine est déjà enregistré. - Promo Recommandé Meilleure alternative Notre FAQ comporte les réponses aux questions fréquentes que vous vous posez peut-être. diff --git a/WordPress/src/main/res/values-gl/strings.xml b/WordPress/src/main/res/values-gl/strings.xml index c2213cdfc68a..c3d6f4b7420b 100644 --- a/WordPress/src/main/res/values-gl/strings.xml +++ b/WordPress/src/main/res/values-gl/strings.xml @@ -603,7 +603,6 @@ Language: gl_ES ONomeDaTuaWeb.com Cor sen etiquetar. %s Como no exemplo superior, un dominio permítelle á xente encontrar e visitar o teu sitio desde o seu navegador. - o primeiro ano Buscar con palabras clave Enviámosche o teu recibo por correo electrónico. %s Pode tardar ata 30 minutos en que o teu dominio personalizado empece a funcionar. @@ -664,7 +663,6 @@ Language: gl_ES Promover unha entrada con Blaze agora Promover esta páxina con Blaze Promover esta entrada con Blaze - Oferta Recomendado Mellor alternativa O teu contido aparecerá en millóns de sitios de WordPress e Tumblr. diff --git a/WordPress/src/main/res/values-he/strings.xml b/WordPress/src/main/res/values-he/strings.xml index 57300936bdb8..be3f50eca8aa 100644 --- a/WordPress/src/main/res/values-he/strings.xml +++ b/WordPress/src/main/res/values-he/strings.xml @@ -936,7 +936,6 @@ Language: he_IL YourSiteName.com לחפש באמצעות מילות מפתח כדאי לחפש דומיין קצר וקליט כדי לעזור לאנשים למצוא את האתר שלך ולבקר בו. - בשנה הראשונה האתר שלך נוצר בהצלחה, אבל נתקלנו בבעיה במהלך ההכנה של הדומיין האישי שלך לתשלום בקופה. יש לנסות שוב או לפנות לתמיכה לעזרה. יידרשו עד 30 דקות להתחלת הפעילות של הדומיין האישי. שלחנו את הקבלה שלך באימייל. %s @@ -1000,7 +999,6 @@ Language: he_IL לקבל תעבודה גדולה יותר לאתר שלך בעזרת Blaze Blaze הדומיין הזה כבר רשום. - מבצע מומלץ החלופה הטובה ביותר כדאי לעיין בשאלות הנפוצות שלנו כדי למצוא מענה על כמה מהשאלות הרגילות שאולי יהיו לך. diff --git a/WordPress/src/main/res/values-id/strings.xml b/WordPress/src/main/res/values-id/strings.xml index 965002cde452..7a3b35bceabb 100644 --- a/WordPress/src/main/res/values-id/strings.xml +++ b/WordPress/src/main/res/values-id/strings.xml @@ -938,7 +938,6 @@ Language: id NamaSitusAnda.com Cari dengan kata kunci Cari domain yang pendek dan mudah diingat agar siapa pun mudah menemukan dan mengunjungi situs Anda. - untuk tahun pertama Situs web Anda berhasil dibuat, namun kami menemukan kendala saat menyiapkan domain khusus Anda selama checkout. Mohon coba lagi atau hubungi bantuan jika diperlukan. Diperlukan 30 menit agar domain khusus Anda dapat berfungsi. Kami telah mengirim e-mail resi Anda. %s @@ -1002,7 +1001,6 @@ Language: id Tingkatkan jumlah pengunjung situs Anda dengan Blaze Blaze Domain ini sudah terdaftar - Obral Disarankan Alternatif Terbaik Tanya Jawab Umum akan menjawab berbagai pertanyaan yang umum diajukan. diff --git a/WordPress/src/main/res/values-it/strings.xml b/WordPress/src/main/res/values-it/strings.xml index ade6ba0cf5c2..9bdcb90baf12 100644 --- a/WordPress/src/main/res/values-it/strings.xml +++ b/WordPress/src/main/res/values-it/strings.xml @@ -949,7 +949,6 @@ Language: it YourSiteName.com Cerca con le parole chiave Cerca un dominio breve e facile da ricordare per aiutare gli utenti a trovare e visitare il tuo sito. - per il primo anno Il tuo sito web è stato creato correttamente, ma abbiamo riscontrato un problema durante la preparazione del dominio personalizzato per il pagamento. Prova di nuovo o contatta il supporto per ricevere assistenza. Potrebbero essere necessari fino a 30 minuti prima che il tuo dominio personalizzato inizi a funzionare. Ti abbiamo inviato la ricevuta tramite email. %s @@ -1013,7 +1012,6 @@ Language: it Attira più traffico sul tuo sito con Blaze Diffondi Questo dominio è già registrato - Offerta Consigliato Alternativa migliore Consulta le domande frequenti per ricevere risposte ai dubbi più comuni che potresti avere. diff --git a/WordPress/src/main/res/values-ja/strings.xml b/WordPress/src/main/res/values-ja/strings.xml index 19050f06e1bd..027645435579 100644 --- a/WordPress/src/main/res/values-ja/strings.xml +++ b/WordPress/src/main/res/values-ja/strings.xml @@ -929,7 +929,6 @@ Language: ja_JP YourSiteName.com キーワードで検索 ユーザーがあなたのサイトを探してアクセスしやすくなる、短く覚えやすいドメインを検索します。 - 最初の年 サイトは正常に作成されましたが、カスタムドメインの購入手続きの準備中に問題が発生しました。 もう一度お試しいただくか、ヘルプが必要な場合はサポートにご連絡ください。 カスタムドメインが使用可能になるまでに最長30分かかる場合があります。 領収書をメールで送信しました。 %s @@ -993,7 +992,6 @@ Language: ja_JP Blaze でサイトのトラフィックを増やす Blaze このドメインはすでに登録されています - セール おすすめ こちらもおすすめ FAQ でよくある質問に対する回答をご確認ください。 diff --git a/WordPress/src/main/res/values-ko/strings.xml b/WordPress/src/main/res/values-ko/strings.xml index 8799dbdfb9dc..8b9df0a961a8 100644 --- a/WordPress/src/main/res/values-ko/strings.xml +++ b/WordPress/src/main/res/values-ko/strings.xml @@ -940,7 +940,6 @@ Language: ko_KR YourSiteName.com 키워드로 검색 사용자가 사이트를 찾고 방문하는 데 도움이 되는 짧고 기억하기 쉬운 도메인을 검색하세요. - 첫해 동안 웹사이트가 생성되었지만, 체크아웃용 사용자 정의 도메인을 준비하는 동안 문제가 발생했습니다. 다시 시도하거나 지원팀에 도움을 문의하세요. 사용자 정의 도메인이 작동하기 시작하려면 30분 정도 걸릴 수 있습니다. 영수증을 이메일로 보내드렸습니다. %s @@ -1004,7 +1003,6 @@ Language: ko_KR Blaze를 통해 사이트에 더 많은 트래픽 유도 Blaze 이 도메인은 이미 등록되었습니다. - 세일 권장 최선의 대안 궁금할 수도 있는 일반적인 질문에 대한 답변은 FAQ를 참조하세요. diff --git a/WordPress/src/main/res/values-lv/strings.xml b/WordPress/src/main/res/values-lv/strings.xml index 09d1521cc410..1292a8d9f3fb 100644 --- a/WordPress/src/main/res/values-lv/strings.xml +++ b/WordPress/src/main/res/values-lv/strings.xml @@ -489,7 +489,6 @@ Language: lv Mēs nosūtījām jūsu kvīti pa e-pastu. %s Var paiet līdz 30 minūtēm, līdz jūsu pielāgotais domēns sāks darboties. Jūsu vietne ir veiksmīgi izveidota, taču, sagatavojot jūsu pielāgoto domēnu norēķiniem, radās problēma. Lūdzu, mēģiniet vēlreiz vai sazinieties ar atbalsta dienestu, lai saņemtu palīdzību. - pirmo gadu Meklējiet īsu un neaizmirstamu domēnu, lai palīdzētu cilvēkiem atrast un apmeklēt jūsu vietni. Meklējiet ar atslēgvārdiem Lietotņu paziņojumi ir atspējoti. Pieskarieties šeit, lai tos iespējotu. @@ -555,7 +554,6 @@ Language: lv Atbildes uz bieži uzdotajiem jautājumiem skatiet mūsu BUJ. Labākā alternatīva Ieteicams - Izpārdošana Šis domēns jau ir reģistrēts Blaze Palieliniet datplūsmu uz savu vietni, izmantojot Blaze diff --git a/WordPress/src/main/res/values-nl/strings.xml b/WordPress/src/main/res/values-nl/strings.xml index 7fc9b437c6f5..25fdc3663c36 100644 --- a/WordPress/src/main/res/values-nl/strings.xml +++ b/WordPress/src/main/res/values-nl/strings.xml @@ -949,7 +949,6 @@ Language: nl JeSiteNaam.com Zoeken met keywords Zoek een kort en gedenkwaardig domein om mensen te helpen je site te vinden en te bezoeken. - voor het eerste jaar Je site is aangemaakt, maar er is een probleem opgetreden bij het afrekenen van je aangepaste domein. Probeer het nog eens of neem contact met ons op voor hulp. Het kan tot 30 minuten duren voor je aangepaste domein werkt. We hebben je betalingsbewijs naar je gemaild. %s @@ -1013,7 +1012,6 @@ Language: nl Zorg dat meer mensen je site bezoeken met Blaze Blaze Dit domein is al geregistreerd - Aanbieding! Aanbevolen Beste alternatief Bekijk onze FAQ voor antwoorden op veelgestelde vragen die je misschien hebt. diff --git a/WordPress/src/main/res/values-pl/strings.xml b/WordPress/src/main/res/values-pl/strings.xml index 25ac32a55d3e..a74d6091374d 100644 --- a/WordPress/src/main/res/values-pl/strings.xml +++ b/WordPress/src/main/res/values-pl/strings.xml @@ -949,7 +949,6 @@ Language: pl NazwaTwojejDomeny.com Szukaj za pomocą słów kluczowych Szukaj krótkiej i zapadającej w pamięć nazwy domeny, żeby pomóc ludziom znaleźć i przejść na twoją witrynę. - za pierwszy rok Twoja witryna internetowa została pomyślnie stworzona, ale napotkaliśmy problem podczas przygotowywania twojej własnej domeny do zakupu. Spróbuj ponownie lub skontaktuj się z pomocą techniczną w celu uzyskania pomocy. Rozpoczęcie prawidłowego działania domeny może potrwać około 30 minut. Wysłaliśmy tobie wiadomość email z paragonem. %s @@ -1013,7 +1012,6 @@ Language: pl Zwiększ ruch na swojej stronie dzięki Blaze Blaze Ta domena jest już zarejestrowana - Promocja Polecane Najlepsza alternatywa Odpowiedzi na najczęstsze pytania znajdziesz w naszej sekcji FAQ. diff --git a/WordPress/src/main/res/values-pt-rBR/strings.xml b/WordPress/src/main/res/values-pt-rBR/strings.xml index a2556dad6879..cdb084193cbe 100644 --- a/WordPress/src/main/res/values-pt-rBR/strings.xml +++ b/WordPress/src/main/res/values-pt-rBR/strings.xml @@ -644,7 +644,6 @@ Language: pt_BR NomeDoSite.com Pesquise com palavras-chave Pesquise um domínio curto mas marcante para ajudar as pessoas a encontrar e visitar seu site. - no primeiro ano Seu site foi criado com sucesso, mas encontramos um problema ao preparar seu domínio personalizado para o checkout. Tente novamente ou entre em contato com o suporte para obter ajuda. Pode levar até 30 minutos para o domínio personalizado começar a funcionar. Enviamos o recibo por e-mail. %s @@ -708,7 +707,6 @@ Language: pt_BR Atraia mais tráfego para seu site com Blaze Blaze Este domínio já está registrado - Promoção Recomendado Melhor alternativa Nossas Perguntas Frequentes podem responder algumas de suas dúvidas. diff --git a/WordPress/src/main/res/values-ro/strings.xml b/WordPress/src/main/res/values-ro/strings.xml index 9f0bd204eaa5..3ef343ea62bf 100644 --- a/WordPress/src/main/res/values-ro/strings.xml +++ b/WordPress/src/main/res/values-ro/strings.xml @@ -947,7 +947,6 @@ Language: ro La fel ca în exemplul de mai sus, un domeniu le permite oamenilor să-ți găsească și să-ți viziteze site-ul din navigatoarele lor web. Activitate recentă Culoare fără etichetă. %s - în primul an Poate să dureze până la 30 de minute până când domeniul tău personalizat va începe să funcționeze. Caută după cuvinte cheie Ți-am trimis chitanța prin email. %s @@ -1016,7 +1015,6 @@ Language: ro Vezi întrebările frecvente pentru răspunsuri la întrebările pe care le ai. Cea mai bună alternativă Recomandat - Reducere Acest domeniu este deja înregistrat Blaze Cu Blaze, aduci mai mult trafic pe site diff --git a/WordPress/src/main/res/values-ru/strings.xml b/WordPress/src/main/res/values-ru/strings.xml index 69df960e2b14..8fa3592ec892 100644 --- a/WordPress/src/main/res/values-ru/strings.xml +++ b/WordPress/src/main/res/values-ru/strings.xml @@ -949,7 +949,6 @@ Language: ru YourSiteName.com Поиск по ключевым словам Выберите короткий и запоминающийся домен, который поможет посетителям найти ваш сайт. - на первый год Веб-сайт создан, но возникла проблема с подготовкой пользовательского домена для оформления заказа. Повторите попытку или обратитесь в службу поддержки. Это может занять до 30 минут, после чего пользовательский домен начнёт работать. Чек отправлен вам на почту. %s @@ -1013,7 +1012,6 @@ Language: ru Повысьте посещаемость своего сайта с помощью Blaze Blaze Этот домен уже зарегистрирован - Распродажа Рекомендуемые Лучшая альтернатива Ищите ответы на типовые вопросы в разделе \"Часто задаваемые вопросы\". diff --git a/WordPress/src/main/res/values-sq/strings.xml b/WordPress/src/main/res/values-sq/strings.xml index b2f17a7e6870..a1c37d0320b0 100644 --- a/WordPress/src/main/res/values-sq/strings.xml +++ b/WordPress/src/main/res/values-sq/strings.xml @@ -843,7 +843,6 @@ Language: sq_AL EmriiSajtitTuaj.com Kërkoni me fjalëkyçe Kërkoni për një përkatësi të shkurtër dhe që mund të mbahet mend, për t’i ndihmuar njerëzit të gjejnë dhe vizitojnë sajtin tuaj. - për vitin e parë Sajti juaj është krijuar me sukses, por hasëm një problem, teksa përgatisnim përkatësinë tuaj vetjake për blerje. Ju lutemi, riprovoni, ose lidhuni me asistencën për ndihmë. Mund të duhen deri në 30 minuta që përkatësia juaj vetjake të fillojë të funksionojë. Ju dërguam faturën tuaj me email. %s @@ -906,7 +905,6 @@ Language: sq_AL Promovoni çfarëdo postimi ose faqeje, brenda pak minutash, për vetëm pak dollarë në ditë. Shpini më tepër trafik te sajti juaj, përmes Blaze-it Kjo përkatësi është e regjistruar tashmë - Ulje çmimesh E rekomanduar Alternativa Më e Mirë Për përgjigje pyetjesh të rëndomta që mund të keni, shihni PBR-të tona. diff --git a/WordPress/src/main/res/values-sv/strings.xml b/WordPress/src/main/res/values-sv/strings.xml index 8d5b09b6a8bd..6ae8e2b2c3b4 100644 --- a/WordPress/src/main/res/values-sv/strings.xml +++ b/WordPress/src/main/res/values-sv/strings.xml @@ -949,7 +949,6 @@ Language: sv_SE YourSiteName.com Sök med nyckelord Leta efter en kort domän som är lätt att komma ihåg för att hjälpa människor hitta och besöka din webbplats. - för första året Din webbplats har skapats, men vi stötte på ett problem när vi skulle förbereda din anpassade domän för betalning. Försök igen eller kontakta supporten för hjälp. Det kan dröja upp till 30 minuter innan din anpassade domän börjar fungera. Vi har skickat ditt kvitto via e-post. %s @@ -1013,7 +1012,6 @@ Language: sv_SE Få mer trafik till din webbplats med Blaze Blaze Denna domän är redan registrerad - Rea Rekommenderat Bästa alternativ Se våra vanliga frågor för svar på vanliga frågor du kan ha. diff --git a/WordPress/src/main/res/values-tr/strings.xml b/WordPress/src/main/res/values-tr/strings.xml index 3fe1531da69b..5bc1e36a173d 100644 --- a/WordPress/src/main/res/values-tr/strings.xml +++ b/WordPress/src/main/res/values-tr/strings.xml @@ -949,7 +949,6 @@ Language: tr SitenizinAdi.com Anahtar sözcük ile arayın Kişilerin sitenizi bulmasına ve ziyaret etmesine yardımcı olacak kısa ve akılda kalıcı bir etki alanı arayın. - ilk yıl için Siteniz oluşturuldu, ancak özel etki alanınızın ödemesini hazırlarken bir sorunla karşılaştık. Lütfen yeniden deneyin ya da yardım almak için destek ekibine başvurun. Özel etki alanınızın çalışmaya başlaması 30 dakika kadar sürebilir. Alındınızı e-posta ile gönderdik. %s @@ -1013,7 +1012,6 @@ Language: tr Blaze ile sitenize daha fazla trafik çekin Blaze Bu etki alanı zaten kaydedilmiş - İndirim Önerilen En iyi alternatif Sık sorulan soruların yanıtları için SSS bölümümüze bakın. diff --git a/WordPress/src/main/res/values-zh-rCN/strings.xml b/WordPress/src/main/res/values-zh-rCN/strings.xml index 667179445361..283c489f2c3c 100644 --- a/WordPress/src/main/res/values-zh-rCN/strings.xml +++ b/WordPress/src/main/res/values-zh-rCN/strings.xml @@ -944,7 +944,6 @@ Language: zh_CN YourSiteName.com 使用关键字搜索 搜索一个简短易记的域名,以帮助访客找到并访问您的站点。 - 第一年 您的网站已成功创建,但我们在准备自定义域名以结账时遇到问题。 请重试或联系支持人员获取帮助。 最多可能需花费 30 分钟时间,您的自定义域名才能开始运行。 我们已将您的收据通过电子邮件发送给您。 %s @@ -1008,7 +1007,6 @@ Language: zh_CN 通过 Blaze 为您的站点吸引更多流量 Blaze 此域名已注册 - 销售 推荐 更好的替代方案 查看我们的常见问题解答,为您可能遇到的常见问题寻找答案。 diff --git a/WordPress/src/main/res/values-zh-rHK/strings.xml b/WordPress/src/main/res/values-zh-rHK/strings.xml index 958c53f35735..e0406bd24d7c 100644 --- a/WordPress/src/main/res/values-zh-rHK/strings.xml +++ b/WordPress/src/main/res/values-zh-rHK/strings.xml @@ -939,7 +939,6 @@ Language: zh_TW YourSiteName.com 透過關鍵字搜尋 搜尋簡短好記的網域,有助於使用者找到並造訪你的網站。 - 第一年 你的網站已成功建立,但準備你的自訂網域以結帳時發生問題。 請再試一次,或聯絡支援團隊取得協助。 你的自訂網域最多可能需要 30 分鐘才能開始運作。 我們已將收據透過電子郵件傳送給你了。 %s @@ -1003,7 +1002,6 @@ Language: zh_TW 使用 Blaze 為你的網站吸引更多流量 Blaze 此網域已被註冊 - 特價 推薦 最佳替代選項 請查看我們的常見問題集,瞭解你可能想知道的一般問題的解答。 diff --git a/WordPress/src/main/res/values-zh-rTW/strings.xml b/WordPress/src/main/res/values-zh-rTW/strings.xml index 958c53f35735..e0406bd24d7c 100644 --- a/WordPress/src/main/res/values-zh-rTW/strings.xml +++ b/WordPress/src/main/res/values-zh-rTW/strings.xml @@ -939,7 +939,6 @@ Language: zh_TW YourSiteName.com 透過關鍵字搜尋 搜尋簡短好記的網域,有助於使用者找到並造訪你的網站。 - 第一年 你的網站已成功建立,但準備你的自訂網域以結帳時發生問題。 請再試一次,或聯絡支援團隊取得協助。 你的自訂網域最多可能需要 30 分鐘才能開始運作。 我們已將收據透過電子郵件傳送給你了。 %s @@ -1003,7 +1002,6 @@ Language: zh_TW 使用 Blaze 為你的網站吸引更多流量 Blaze 此網域已被註冊 - 特價 推薦 最佳替代選項 請查看我們的常見問題集,瞭解你可能想知道的一般問題的解答。 diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index a49d42cbfcb6..94b1599b6c03 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -3713,11 +3713,9 @@ A good name is short and memorable.\nYou can change it later. - for the first year Free for the first year with annual paid plans Best Alternative Recommended - Sale This domain is already registered Purchase domain Continue with subdomain diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt index fc3c95e7fe33..4cbc0e498fad 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt @@ -5,7 +5,6 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import org.assertj.core.api.Assertions.assertThat import org.junit.Before -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor @@ -23,15 +22,7 @@ import org.mockito.kotlin.times import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.wordpress.android.BaseUnitTest -import org.wordpress.android.Constants.TYPE_DOMAINS_PRODUCT import org.wordpress.android.R -import org.wordpress.android.fluxc.Dispatcher -import org.wordpress.android.fluxc.model.products.Product -import org.wordpress.android.fluxc.network.rest.wpcom.site.DomainSuggestionResponse -import org.wordpress.android.fluxc.store.ProductsStore -import org.wordpress.android.fluxc.store.ProductsStore.OnProductsFetched -import org.wordpress.android.fluxc.store.SiteStore.OnSuggestedDomains -import org.wordpress.android.fluxc.store.SiteStore.SuggestDomainError import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.DomainsUiState import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.DomainsUiState.CreateSiteButtonState import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.DomainsUiState.DomainsUiContentState @@ -43,29 +34,26 @@ import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewMode import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.usecases.FETCH_DOMAINS_VENDOR_DOT import org.wordpress.android.ui.sitecreation.usecases.FETCH_DOMAINS_VENDOR_MOBILE +import org.wordpress.android.ui.sitecreation.usecases.FetchDomainsResult import org.wordpress.android.ui.sitecreation.usecases.FetchDomainsUseCase import org.wordpress.android.ui.utils.UiString.UiStringRes import org.wordpress.android.util.NetworkUtilsWrapper import org.wordpress.android.util.config.PlansInSiteCreationFeatureConfig +import uniffi.wp_api.DomainSuggestion +import uniffi.wp_api.FreeDomainSuggestion +import uniffi.wp_api.PaidDomainSuggestion import kotlin.test.assertIs private const val MULTI_RESULT_DOMAIN_FETCH_RESULT_SIZE = 20 private val MULTI_RESULT_DOMAIN_FETCH_QUERY = "multi_result_query" to MULTI_RESULT_DOMAIN_FETCH_RESULT_SIZE private val EMPTY_RESULT_DOMAIN_FETCH_QUERY = "empty_result_query" to 0 -private val SALE_PRODUCTS = listOf(Product(productId = 3, saleCost = 1.0, currencyCode = "EUR")) @ExperimentalCoroutinesApi @RunWith(MockitoJUnitRunner::class) class SiteCreationDomainsViewModelTest : BaseUnitTest() { - @Mock - lateinit var dispatcher: Dispatcher - @Mock lateinit var fetchDomainsUseCase: FetchDomainsUseCase - @Mock - private lateinit var productsStore: ProductsStore - @Mock lateinit var plansInSiteCreationFeatureConfig: PlansInSiteCreationFeatureConfig @@ -97,9 +85,7 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { viewModel = SiteCreationDomainsViewModel( networkUtils = networkUtils, domainSanitizer = mSiteCreationDomainSanitizer, - dispatcher = dispatcher, fetchDomainsUseCase = fetchDomainsUseCase, - productsStore = productsStore, plansInSiteCreationFeatureConfig = plansInSiteCreationFeatureConfig, tracker = tracker, bgDispatcher = testDispatcher(), @@ -127,8 +113,8 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { whenever(mSiteCreationDomainSanitizer.sanitizeDomainQuery(any())).thenReturn( createSanitizedDomainResult(isDomainAvailableInSuggestions) ) - whenever(fetchDomainsUseCase.fetchDomains(eq(queryResultSizePair.first), any(), any(), any())).thenReturn( - createSuccessfulOnSuggestedDomains(queryResultSizePair) + whenever(fetchDomainsUseCase.fetchDomains(eq(queryResultSizePair.first), any(), any())).thenReturn( + createSuccessfulFetchResult(queryResultSizePair) ) block() } @@ -214,13 +200,13 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { */ @Test fun verifyNonEmptyUpdateQueryUiStateAfterErrorResponse() = test { - val queryResultErrorPair = "error_result_query" to "GENERIC_ERROR" - whenever(fetchDomainsUseCase.fetchDomains(eq(queryResultErrorPair.first), any(), any(), any())).thenReturn( - createFailedOnSuggestedDomains(queryResultErrorPair) + val errorQuery = "error_result_query" + whenever(fetchDomainsUseCase.fetchDomains(eq(errorQuery), any(), any())).thenReturn( + FetchDomainsResult.Error(type = "empty_query", message = "Query is empty") ) viewModel.start() - viewModel.onQueryChanged(queryResultErrorPair.first) + viewModel.onQueryChanged(errorQuery) advanceUntilIdle() val captor = ArgumentCaptor.forClass(DomainsUiState::class.java) @@ -234,18 +220,32 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { .isInstanceOf(Old.ErrorItemUiState::class.java) } + @Test + fun `verify the api error type and message are tracked`() = test { + val errorQuery = "error_result_query" + whenever(fetchDomainsUseCase.fetchDomains(eq(errorQuery), any(), any())).thenReturn( + FetchDomainsResult.Error(type = "empty_query", message = "Query is empty") + ) + + viewModel.start() + viewModel.onQueryChanged(errorQuery) + advanceUntilIdle() + + verify(tracker).trackErrorShown("domains", "empty_query", "Query is empty") + } + /** * Verifies the UI state for after the user enters a non-empty query which results in INVALID_QUERY error. */ @Test fun verifyNonEmptyUpdateQueryUiStateAfterErrorResponseOfTypeInvalidQuery() = test { - val queryResultErrorPair = "empty_result_query_invalid" to "INVALID_QUERY" - whenever(fetchDomainsUseCase.fetchDomains(eq(queryResultErrorPair.first), any(), any(), any())).thenReturn( - createFailedOnSuggestedDomains(queryResultErrorPair) + val invalidQuery = "empty_result_query_invalid" + whenever(fetchDomainsUseCase.fetchDomains(eq(invalidQuery), any(), any())).thenReturn( + FetchDomainsResult.InvalidQuery ) viewModel.start() - viewModel.onQueryChanged(queryResultErrorPair.first) + viewModel.onQueryChanged(invalidQuery) advanceUntilIdle() val captor = ArgumentCaptor.forClass(DomainsUiState::class.java) @@ -338,7 +338,6 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { eq(MULTI_RESULT_DOMAIN_FETCH_QUERY.first), eq(FETCH_DOMAINS_VENDOR_DOT), eq(true), - eq(MULTI_RESULT_DOMAIN_FETCH_QUERY.second), ) } @@ -355,36 +354,62 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { private fun testNewUi(block: suspend CoroutineScope.() -> Unit) = test { whenever(plansInSiteCreationFeatureConfig.isEnabled()).thenReturn(true) - whenever(productsStore.fetchProducts(any())).thenReturn(mock()) block() } private fun testWithSuccessResultNewUi( queryToSize: Pair = MULTI_RESULT_DOMAIN_FETCH_QUERY, - block: suspend CoroutineScope.(OnSuggestedDomains) -> T + block: suspend CoroutineScope.(List) -> T ) = testNewUi { val (query, size) = queryToSize val suggestions = List(size) { - DomainSuggestionResponse().apply { - domain_name = if (it == 0) query else "$query-$it.com" - is_free = it % 2 == 0 - cost = if (is_free) "Free" else "$$it.00" - product_id = it - supports_privacy = !is_free + val name = if (it == 0) query else "$query-$it.com" + val isFree = it % 2 == 0 + if (isFree) { + DomainSuggestion.Free( + FreeDomainSuggestion( + domainName = name, + cost = "Free", + isFree = true, + ) + ) + } else { + DomainSuggestion.Paid( + PaidDomainSuggestion( + domainName = name, + relevance = 0.0, + supportsPrivacy = true, + vendor = "donuts", + matchReasons = emptyList(), + maxRegYears = 10u, + multiYearRegAllowed = true, + productId = it.toULong(), + productSlug = "domain_reg", + cost = "$$it.00", + renewCost = "$$it.00", + renewRawPrice = (it * 100).toLong(), + rawPrice = (it * 100).toLong(), + currencyCode = "USD", + saleCost = null, + hstsRequired = null, + policyNotices = emptyList(), + ) + ) } } - val event = OnSuggestedDomains(query, suggestions) - whenever(fetchDomainsUseCase.fetchDomains(any(), any(), any(), any())).thenReturn(event) - block(event) + val result = FetchDomainsResult.Success(suggestions) + whenever(fetchDomainsUseCase.fetchDomains(any(), any(), any())) + .thenReturn(result) + block(suggestions) } private val uiDomains get() = assertIs>(viewModel.uiState.value?.contentState?.items) @Test fun verifyFetchFreeAndPaidDomainsWhenPurchasingFeatureConfigIsEnabled() = testWithSuccessResultNewUi { - val (query, size) = MULTI_RESULT_DOMAIN_FETCH_QUERY + val query = MULTI_RESULT_DOMAIN_FETCH_QUERY.first viewModel.start() viewModel.onQueryChanged(query) @@ -394,18 +419,9 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { eq(query), eq(FETCH_DOMAINS_VENDOR_MOBILE), eq(false), - eq(size), ) } - @Test - fun `verify domain products are fetched only at first start`() = testNewUi { - viewModel.start() - viewModel.start() - - verify(productsStore).fetchProducts(eq(TYPE_DOMAINS_PRODUCT)) - } - @Test fun `verify create site button text changes when selecting a free domain`() = testNewUi { viewModel.start() @@ -424,20 +440,21 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { assertIs(viewModel.uiState.value?.createSiteButtonState) } - @Test - fun `verify all domain results from api are visible`() = testWithSuccessResultNewUi { (query, results) -> + fun `verify all domain results from api are visible`() = testWithSuccessResultNewUi { suggestions -> + val query = MULTI_RESULT_DOMAIN_FETCH_QUERY.first viewModel.start() viewModel.onQueryChanged(query) advanceUntilIdle() - assertThat(uiDomains).hasSameSizeAs(results) + assertThat(uiDomains).hasSameSizeAs(suggestions) } @Test - fun `verify cost of free domain results from api is 'Free'`() = testWithSuccessResultNewUi { (query, results) -> - val apiFreeDomains = results.filter { it.is_free } + fun `verify cost of free domain results from api is 'Free'`() = testWithSuccessResultNewUi { suggestions -> + val query = MULTI_RESULT_DOMAIN_FETCH_QUERY.first + val apiFreeDomains = suggestions.filterIsInstance() viewModel.start() viewModel.onQueryChanged(query) @@ -447,8 +464,9 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { } @Test - fun `verify cost of paid domain results from api is 'Paid'`() = testWithSuccessResultNewUi { (query, results) -> - val apiPaidDomains = results.filter { !it.is_free } + fun `verify cost of paid domain results from api is 'Paid'`() = testWithSuccessResultNewUi { suggestions -> + val query = MULTI_RESULT_DOMAIN_FETCH_QUERY.first + val apiPaidDomains = suggestions.filterIsInstance() viewModel.start() viewModel.onQueryChanged(query) @@ -457,32 +475,9 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { assertThat(uiDomains).filteredOn { it.cost is Cost.Paid }.hasSameSizeAs(apiPaidDomains) } - @Test @Ignore("It is removed from UI for now, for being Free with annual plan") - fun `verify cost of sale domain results from api is 'OnSale'`() = testWithSuccessResultNewUi { (query) -> - whenever(productsStore.fetchProducts(any())).thenReturn(OnProductsFetched(SALE_PRODUCTS)) - - viewModel.start() - - viewModel.onQueryChanged(query) - advanceUntilIdle() - - assertThat(uiDomains).filteredOn { it.cost is Cost.OnSale }.hasSameSizeAs(SALE_PRODUCTS) - } - - @Test @Ignore("It is removed from UI for now, for being Free with annual plan") - fun `verify sale domain results from api have tag 'Sale'`() = testWithSuccessResultNewUi { (query) -> - whenever(productsStore.fetchProducts(any())).thenReturn(OnProductsFetched(SALE_PRODUCTS)) - - viewModel.start() - - viewModel.onQueryChanged(query) - advanceUntilIdle() - - assertThat(uiDomains.flatMap { it.tags }).filteredOn { it is Tag.Sale }.hasSameSizeAs(SALE_PRODUCTS) - } - @Test - fun `verify only 1st domain result from api is 'Recommended'`() = testWithSuccessResultNewUi { (query) -> + fun `verify only 1st domain result from api is 'Recommended'`() = testWithSuccessResultNewUi { + val query = MULTI_RESULT_DOMAIN_FETCH_QUERY.first viewModel.start() viewModel.onQueryChanged(query) @@ -492,7 +487,8 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { } @Test - fun `verify only 2nd domain result from api is 'BestAlternative'`() = testWithSuccessResultNewUi { (query) -> + fun `verify only 2nd domain result from api is 'BestAlternative'`() = testWithSuccessResultNewUi { + val query = MULTI_RESULT_DOMAIN_FETCH_QUERY.first viewModel.start() viewModel.onQueryChanged(query) @@ -502,7 +498,8 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { } @Test - fun `verify selected domain is propagated to UI on click`() = testWithSuccessResultNewUi { (query) -> + fun `verify selected domain is propagated to UI on click`() = testWithSuccessResultNewUi { + val query = MULTI_RESULT_DOMAIN_FETCH_QUERY.first viewModel.start() viewModel.onQueryChanged(query) @@ -576,25 +573,19 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { } /** - * Helper function that creates an [OnSuggestedDomains] event for the given query and number of results pair. + * Helper function that creates a [FetchDomainsResult.Success] for the given query and number of results pair. */ - private fun createSuccessfulOnSuggestedDomains(queryResultSizePair: Pair): OnSuggestedDomains { + private fun createSuccessfulFetchResult(queryResultSizePair: Pair): FetchDomainsResult.Success { val suggestions = (0 until queryResultSizePair.second).map { - val response = DomainSuggestionResponse() - response.domain_name = "${queryResultSizePair.first}-$it.wordpress.com" - response + DomainSuggestion.Free( + FreeDomainSuggestion( + domainName = "${queryResultSizePair.first}-$it.wordpress.com", + cost = "Free", + isFree = true, + ) + ) } - return OnSuggestedDomains(queryResultSizePair.first, suggestions) - } - - /** - * Helper function that creates an error [OnSuggestedDomains] event. - */ - private fun createFailedOnSuggestedDomains(queryResultErrorPair: Pair): OnSuggestedDomains { - return OnSuggestedDomains(queryResultErrorPair.first, emptyList()) - .apply { - error = SuggestDomainError(queryResultErrorPair.second, "test") - } + return FetchDomainsResult.Success(suggestions) } /** diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/usecases/FetchDomainsUseCaseTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/usecases/FetchDomainsUseCaseTest.kt index 7be32e3937b4..dd9016426e74 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/usecases/FetchDomainsUseCaseTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/usecases/FetchDomainsUseCaseTest.kt @@ -1,23 +1,24 @@ package org.wordpress.android.ui.sitecreation.usecases import kotlinx.coroutines.ExperimentalCoroutinesApi -import org.junit.Assert.assertEquals +import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.KArgumentCaptor import org.mockito.kotlin.any -import org.mockito.kotlin.argumentCaptor -import org.mockito.kotlin.verify +import org.mockito.kotlin.verifyNoInteractions import org.mockito.kotlin.whenever import org.wordpress.android.BaseUnitTest -import org.wordpress.android.fluxc.Dispatcher -import org.wordpress.android.fluxc.annotations.action.Action -import org.wordpress.android.fluxc.store.SiteStore -import org.wordpress.android.fluxc.store.SiteStore.OnSuggestedDomains -import org.wordpress.android.fluxc.store.SiteStore.SuggestDomainsPayload +import org.wordpress.android.fluxc.store.AccountStore +import org.wordpress.android.networking.restapi.WpComApiClientProvider +import rs.wordpress.api.kotlin.WpComApiClient +import rs.wordpress.api.kotlin.WpRequestResult +import uniffi.wp_api.DomainSuggestion +import uniffi.wp_api.FreeDomainSuggestion +import uniffi.wp_api.RequestMethod +import uniffi.wp_api.WpErrorCode private const val SEARCH_QUERY = "test" @@ -25,28 +26,157 @@ private const val SEARCH_QUERY = "test" @RunWith(MockitoJUnitRunner::class) class FetchDomainsUseCaseTest : BaseUnitTest() { @Mock - lateinit var dispatcher: Dispatcher + lateinit var wpComApiClientProvider: WpComApiClientProvider @Mock - lateinit var store: SiteStore + lateinit var accountStore: AccountStore + + @Mock + lateinit var wpComApiClient: WpComApiClient + private lateinit var useCase: FetchDomainsUseCase - private lateinit var dispatchCaptor: KArgumentCaptor> - private val event = OnSuggestedDomains(SEARCH_QUERY, emptyList()) @Before fun setUp() { - useCase = FetchDomainsUseCase(dispatcher, store) - dispatchCaptor = argumentCaptor() + whenever(accountStore.accessToken).thenReturn("test-token") + whenever(wpComApiClientProvider.getWpComApiClient("test-token")) + .thenReturn(wpComApiClient) + useCase = FetchDomainsUseCase(wpComApiClientProvider, accountStore) } + @Suppress("UNCHECKED_CAST") @Test - fun coroutineResumedWhenResultEventDispatched() = test { - whenever(dispatcher.dispatch(any())).then { useCase.onSuggestedDomains(event) } + fun `given successful response, when fetchDomains, then return Success with suggestions`() = + test { + val suggestions = listOf( + DomainSuggestion.Free( + FreeDomainSuggestion( + domainName = "$SEARCH_QUERY.wordpress.com", + cost = "Free", + isFree = true, + ) + ) + ) + whenever(wpComApiClient.request(any())) + .thenReturn( + WpRequestResult.Success(suggestions) + as WpRequestResult + ) - val resultEvent = useCase.fetchDomains(SEARCH_QUERY, "vendor", onlyWordpressCom = false) + val result = useCase.fetchDomains( + SEARCH_QUERY, "vendor", onlyWordpressCom = false + ) - verify(dispatcher).dispatch(dispatchCaptor.capture()) - assertEquals(dispatchCaptor.lastValue.payload.query, SEARCH_QUERY) - assertEquals(event, resultEvent) - } + assertThat(result).isInstanceOf(FetchDomainsResult.Success::class.java) + val success = result as FetchDomainsResult.Success + assertThat(success.suggestions).hasSize(1) + } + + @Suppress("UNCHECKED_CAST") + @Test + fun `given error response, when fetchDomains, then return Error`() = + test { + whenever(wpComApiClient.request(any())) + .thenReturn( + WpRequestResult.UnknownError( + 500.toUInt(), + "Internal Server Error", + "", + RequestMethod.GET, + ) + ) + + val result = useCase.fetchDomains( + SEARCH_QUERY, "vendor", onlyWordpressCom = false + ) + + assertThat(result).isEqualTo( + FetchDomainsResult.Error(type = "GENERIC_ERROR", message = null) + ) + } + + @Suppress("UNCHECKED_CAST") + @Test + fun `given invalid_query error, when fetchDomains, then return InvalidQuery`() = + test { + whenever(wpComApiClient.request(any())) + .thenReturn(wpError("invalid_query", "Domain searches must contain a word")) + + val result = useCase.fetchDomains( + SEARCH_QUERY, "vendor", onlyWordpressCom = false + ) + + assertThat(result).isEqualTo(FetchDomainsResult.InvalidQuery) + } + + @Suppress("UNCHECKED_CAST") + @Test + fun `given empty_results error, when fetchDomains, then return Success with no suggestions`() = + test { + whenever(wpComApiClient.request(any())) + .thenReturn(wpError("empty_results", "No available domains for that search.")) + + val result = useCase.fetchDomains( + SEARCH_QUERY, "vendor", onlyWordpressCom = false + ) + + assertThat(result).isEqualTo(FetchDomainsResult.Success(emptyList())) + } + + @Suppress("UNCHECKED_CAST") + @Test + fun `given another api error, when fetchDomains, then return Error carrying its code`() = + test { + whenever(wpComApiClient.request(any())) + .thenReturn(wpError("empty_query", "Query is empty")) + + val result = useCase.fetchDomains( + SEARCH_QUERY, "vendor", onlyWordpressCom = false + ) + + assertThat(result).isEqualTo( + FetchDomainsResult.Error(type = "empty_query", message = "Query is empty") + ) + } + + @Test + fun `given a signed out account, when fetchDomains, then report the missing token`() = + test { + // What `AccountStore` returns when signed out, despite its nullable type. + whenever(accountStore.accessToken).thenReturn("") + + val result = useCase.fetchDomains( + SEARCH_QUERY, "vendor", onlyWordpressCom = false + ) + + assertThat(result).isEqualTo( + FetchDomainsResult.Error(type = "NO_ACCESS_TOKEN", message = null) + ) + verifyNoInteractions(wpComApiClient) + } + + @Test + fun `given a null access token, when fetchDomains, then report it instead of crashing`() = + test { + whenever(accountStore.accessToken).thenReturn(null) + + val result = useCase.fetchDomains( + SEARCH_QUERY, "vendor", onlyWordpressCom = false + ) + + assertThat(result).isEqualTo( + FetchDomainsResult.Error(type = "NO_ACCESS_TOKEN", message = null) + ) + verifyNoInteractions(wpComApiClient) + } + + @Suppress("UNCHECKED_CAST") + private fun wpError(code: String, message: String) = WpRequestResult.WpError( + errorCode = WpErrorCode.CustomException(code), + errorMessage = message, + statusCode = 400.toUInt(), + response = "", + requestUrl = "", + requestMethod = RequestMethod.GET, + ) as WpRequestResult }